Search code examples
c#wpfwpfdatagriddatatemplatedatagridtemplatecolumn

How do I update the CellTemplate DataTemplate control when the CellEditingTemplate DataTemplate control changes its bound value?


I have a Template Column in my DataGrid that looks like this:

<DataGridTemplateColumn>
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Item}" />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
    <DataGridTemplateColumn.CellEditingTemplate>
        <DataTemplate>
            <ComboBox
                DisplayMemberPath="Item"
                Header="Item"
                ItemsSource="{Binding Data.AssetDescriptions, Source={StaticResource proxy}}"
                SelectedValueBinding="{Binding AssetDescriptionID}"
                SelectedValuePath="AssetDescriptionID" />
        </DataTemplate>
    </DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>

The ViewModel has a public property containing the Asset Descriptions:

public IEnumerable<AssetDescription> AssetDescriptions { get; set; }

Where AssetDescription is essentially:

public class AssetDescription
{
    public int AssetDescriptionID { get; set; }
    public string Item { get; set; } // Description
}

The DataGrid itself is bound to an ObservableCollection<Asset> Assets property, where Asset contains both AssetDescriptionID and Item (description). To accomplish that, I join the Assets table to the AssetDescriptions table, like so:

var assets = _conn.Query<Asset>(
                @"SELECT A.AssetDescriptionID, D.Item 
                    FROM Assets A
                    JOIN AssetDescriptions D
                      ON D.AssetDescriptionID = A.AssetDescriptionID");

Assets = new ObservableCollection<Asset>(assets);

This all works perfectly, except that the TextBlock in the CellTemplate DataTemplate does not get updated to the new description when a new value is selected in the ComboBox.

How do I accomplish that?


Solution

  • The problem is that you only bind to the AssetDescriptionID-Property of your Asset. Item will never be touched (which your CellTemplate binds to).

    Option 1:
    Try using a DataGridComboBoxColumn instead of DataGridTemplateColumn
    Item (on Asset) is then no longer needed

    <DataGridComboBoxColumn 
        DisplayMemberPath="Item"
        Header="Item"
        ItemsSource="{Binding Data.AssetDescriptions, Source={StaticResource proxy}}"
        SelectedValueBinding="{Binding AssetDescriptionID}"
        SelectedValuePath="AssetDescriptionID">
    </DataGridComboBoxColumn>
    

    Option 2: If you really need the Item/description on your Asset
    Easiest solution will be to bind the whole object(AssetDescription).

    Change your Asset to this

    class Asset
    {
        ...
        public AssetDescription AssetDescription {get;set;}
        ...
    }
    

    And your CellEditingTemplate to this

    <DataTemplate>
        <ComboBox
            DisplayMemberPath="Item"
            ItemsSource="{Binding Data.AssetDescriptions, Source={StaticResource proxy}}"
            SelectedItem="{Binding AssetDescription }" />
    </DataTemplate>
    

    And CellTemplate to this

    <TextBlock Text="{Binding AssetDescription.Item}" />
    

    Edit: You can also use a DataGridComboBoxColumn for Option 2

    <DataGridComboBoxColumn 
        DisplayMemberPath="Item"
        Header="Item"
        ItemsSource="{Binding Data.AssetDescriptions, Source={StaticResource proxy}}"
        SelectedItemBinding="{Binding AssetDescription}">
    </DataGridComboBoxColumn>