Saturday, November 29

Refresh CellTemplate in ListView When Content Changes

There is one thing (at least) in WPF which lack update mechanism and that is DataTemplateSelector.
Imagine you implement a property grid inside a ListView control. You will have three columns: Name, Type, Value.
Name is easy, it is just a TextBox, Type is also easy, is it a combo box from which you select predefine types (string, integer, date, color).
The hard one is Value since its template has to be changed when the Type is change.

The Problem: DataTemplateSelector does not have a way of signaling that the template needs to be re-evaluated. Once WPF select a template it will stay with it.

The Solution: The solution for re-evaluating data template selector for ListView is to refresh the DataTemplateSelector bound to the column's CellTemplateSelector property.

The Explanation: I'm a fan of M-V-VM paradigm, so I usually have my UserControl or Window's DataContext property set to an instance of my ViewModel class.
In my XAML, I bind my GridColumn's CellTemplateSelector property to my TemplateSelector property of my ViewModel.

Code:

internal class EditActionPropertiesViewModel
{
private DataTemplateSelector m_ValueDataTemplateSelector = null;

public DataTemplateSelector ValueDataTemplateSelector
{
get { return m_ValueDataTemplateSelector; }
private set
{
m_ValueDataTemplateSelector = value;
OnPropertyChanged("ValueDataTemplateSelector");
}
}

internal void RefreshValueTemplateSelector()
{
ValueDataTemplateSelector = new ValueEditorCellTemplateSelector();
}
}

XAML:



<UserControl>
<ListView>
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Type" CellTemplate="{StaticResource TypeCellTemplate}">
<GridViewColumn Header="Value" CellTemplateSelector="{Binding ValueDataTemplateSelector}">
    </GridView.Columns>
   </GridView>
  </ListView.View>
 </ListView>
</UserControl>
Remember that the DataContext of the grid column is the ViewModel, not each ListViewItem's DataItem.
So, any time any of the properties' Type changes, we need to signal that the TemplateSelector property has change and WPF will re-evaluate the data templates.