4

I have 2 templates for DataGrid's CellTemplate. When I change the items, it won't help me select the template for me, my DisplayModeTemplateSelector won't even be called!

What I'm wondering is if there is a way to trigger this CellTemplateSelector again when items changed? How to refresh CellTemplate in DataGrid or ListView When Content Changes

<DataGridTemplateColumn x:Name="colorRange"
                        Width="*"
                        Header="Color Range">
    <DataGridTemplateColumn.CellTemplateSelector>
        <local:DisplayModeTemplateSelector HeatMapTemplate="{StaticResource heatMapTemplate}" ThreshHoldTemplate="{StaticResource threshHoldTemplate}" />
    </DataGridTemplateColumn.CellTemplateSelector>
</DataGridTemplateColumn>

I found this blog http://dotdotnet.blogspot.com/2008/11/refresh-celltemplate-in-listview-when.html

I think this is similar with my problem, but I really can't understand him! Can anyone explain it?

CodingTT
  • 1,125
  • 3
  • 14
  • 23

2 Answers2

4

The solution in the blog post will not work with the DataGrid control because the DataGridTemplateColumn class doesn't belong to the Visual Tree, and even when I tried to bind it to a static class, I didn't suceed because of strange exceptions after property changes.

Anyway there is two possible ways to solve this problem.

1) The easier way.

Using the ObservableCollection class.

    var itemIndex = 0;
    var currentItem = vm.Items[itemIndex];
    //Change necessary properties
    //..
    vm.Items.Remove(currentItem);
    vm.Items.Insert(itemIndex, currentItem);      

2) The more complex way.

You can add to your item class the property which returns the object itself.

    public ItemViewModel(/*...*/)
    {
        this.SelfProperty = this;
        //...
    }

    public ItemViewModel SelfProperty { get; private set; }

    public void Update()
    {
        this.SelfProperty = null;
        this.OnPropertyChanged("SelfProperty");
        this.SelfProperty = this;
        this.OnPropertyChanged("SelfProperty");
    }

After that you can use the ContentControl.ContentTemplateSelector instead of the CellTemplateSelector like this:

            <DataGridTemplateColumn Header="Color Range">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <ContentControl Content="{Binding SelfProperty}"  ContentTemplateSelector="{StaticResource mySelector}" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>

And when you change the property, call the Update method somehow:

  currentItem.SomeDataProperty = "some new value";
  //Or you can add this method call to the OnPropertyChanged 
  //so that it calls authomatically
  currentItem.Update(); 

The reason why I've set a null value to the SelfProperty in the Update method first, is that the Selector will not update a template until the Content property is completely changed. If I set the same object once again - nothing will happen, but if I set a null value to it first - changes will be handled.

vortexwolf
  • 13,967
  • 2
  • 54
  • 72
  • this is a great post! thank you very much. I usually figure everything out myself, but this issue has really stumped me for a day! Thanks again. I wish I could give you more than +1 – denis morozov Apr 26 '12 at 15:16
2

The easy way is to hook the Combo Box's Selection Changed event, and reassign the template selector. This forces a refresh.

In XAML (assume the rest of the DataGrid/ComboBoxColumn:

<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
    <Setter Property="ItemsSource" 
            Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}},  Path=DataContext.Gates, UpdateSourceTrigger=PropertyChanged}"/>
    <EventSetter Event="SelectionChanged" Handler="GateIDChanged" />
</Style>

That refers to this DataGridTemplateColumn:

<DataGridTemplateColumn x:Name="GateParamsColumn" Header="Gate Parameters" CellTemplateSelector="{StaticResource GateParamsTemplateSelector}"></DataGridTemplateColumn>

And in the code behind:

private void GateIDChanged(object sender, SelectionChangedEventArgs eventArgs)
{
    var selector = GateParamsColumn.CellTemplateSelector;
    GateParamsColumn.CellTemplateSelector = null;
    GateParamsColumn.CellTemplateSelector = selector;
}
TarkaDaal
  • 18,798
  • 7
  • 34
  • 51
  • This worked great. I might have made a mistake, yet I had to change UpdateTrigger to LostFocus for it to work as soon as I change the ComboBox value. – user3141326 Oct 12 '15 at 17:41