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.

5 comments:

  1. Hi Ido Ran,

    I am happy to see your blog, because I am finding a solution for this "re-evaluating the CellTempalteSelector" problem.
    Unfortunately, I can not understand yours clearly.. :(( If you sent a complete little example, I would be glad.

    Many thanks,
    Tibor

    ReplyDelete
  2. Dear Tibor,
    My idea relay on the fact you can data bind a CellTemplate to a property (say call it MyTemplate property) and then when refresh is needed you can use the code OnPropertyChanged("MyProperty") to force WPF to refresh the template.

    If you want me to send you a working sample please send me an email to ido.ran@gmail.com and I'll create one.

    Ido.

    ReplyDelete
  3. Hi Ido Ran,

    Thanks for your answer, I wrote a mail to you. To tell the truth, my problem is the next one:
    I have got a ListView with dataBinding. I would like to modify the color of the ListViewItem based on any property of the binding data.

    Thanks your help,
    Tibor

    ReplyDelete
  4. Big Thx for you Post!

    ReplyDelete
  5. View model knows about hows it displays in UI??? (view model should not contain any informations about it data templates)

    ReplyDelete