Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF: Reapply DataTemplateSelector when a certain value changes

So here is the XAML that I have:

<ItemsControl ItemsSource="{Binding Path=Groups}" ItemTemplateSelector="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=ListTemplateSelector}"/> 

Here is my ListTemplateSelector class:

public class ListTemplateSelector : DataTemplateSelector { public DataTemplate GroupTemplate { get; set; } public DataTemplate ItemTemplate { get; set; } public override DataTemplate SelectTemplate(object item, DependencyObject container) {     GroupList<Person> list = item as GroupList<Person>;     if (list != null && !list.IsLeaf)         return GroupTemplate;     return ItemTemplate; } } 

The GroupTemplate data template references the ListTemplateSelector inside itself, so this is why I have set up like I have it set up. It's the only recursive hack I could put together. But that's not the problem I'm having.

My problem is, I want to change from ItemTemplate to GroupTemplate when the IsLeaf property changes. This works beautifully the very first time since it reads the property the first time. But once this property changes, the template selector doesn't get reapplied. Now, I could use triggers to bind to the value and set the item template appropriately, but I need to be able to set a different template for each item, as they could be in a different state.

For instance, say I have a list of groups like this:

Group 1: IsLeaf = false, so template = GroupTemplate

Group 2: IsLeaf = true, so template = ItemTemplate

Group 3: IsLeaf = false, so template = GroupTemplate

And once group 1's IsLeaf property changes to true, the template needs to automatically change to ItemTemplate.

EDIT:

Here is my temporary solution. Any better way to do it?

<ItemsControl ItemsSource="{Binding Path=Groups}"> <ItemsControl.ItemTemplate>     <DataTemplate>         <ContentControl Content="{Binding}">             <ContentControl.Style>                 <Style TargetType="{x:Type ContentControl}">                     <Setter Property="ContentTemplate" Value="{DynamicResource ItemTemplate}"/>                     <Style.Triggers>                         <DataTrigger Binding="{Binding Path=IsLeaf}" Value="False">                             <Setter Property="ContentTemplate" Value="{DynamicResource GroupTemplate}"/>                         </DataTrigger>                     </Style.Triggers>                 </Style>             </ContentControl.Style>         </ContentControl>     </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> 
like image 358
Nick Avatar asked Aug 22 '10 21:08

Nick


2 Answers

Regarding your EDIT, wouldn't a DataTemplate Trigger be enough instead of using a Style? That is:

<ItemsControl ItemsSource="{Binding Path=Groups}">     <ItemsControl.ItemTemplate>         <DataTemplate>             <ContentControl x:Name="cc" Content="{Binding}" ContentTemplate="{DynamicResource ItemTemplate}"/>              <DataTemplate.Triggers>                 <DataTrigger Binding="{Binding Path=IsLeaf}" Value="False">                     <Setter TargetName="cc" Property="ContentTemplate" Value="{DynamicResource GroupTemplate}"/>                 </DataTrigger>             </DataTemplate.Triggers>                                     </DataTemplate>     </ItemsControl.ItemTemplate> </ItemsControl> 
like image 120
ASanch Avatar answered Sep 22 '22 05:09

ASanch


I found this workaround that seems easier to me. From within the TemplateSelector listen to the property that your care about and then reapply the template selector to force a refresh.

public class DataSourceTemplateSelector : DataTemplateSelector {     public DataTemplate IA { get; set; }     public DataTemplate Dispatcher { get; set; }     public DataTemplate Sql { get; set; }      public override DataTemplate SelectTemplate(object item, System.Windows.DependencyObject container)     {         var ds = item as DataLocationViewModel;         if (ds == null)         {             return base.SelectTemplate(item, container);         }         PropertyChangedEventHandler lambda = null;         lambda = (o, args) =>             {                 if (args.PropertyName == "SelectedDataSourceType")                 {                     ds.PropertyChanged -= lambda;                     var cp = (ContentPresenter)container;                     cp.ContentTemplateSelector = null;                     cp.ContentTemplateSelector = this;                                         }             };         ds.PropertyChanged += lambda;          switch (ds.SelectedDataSourceType.Value)         {             case DataSourceType.Dispatcher:                 return Dispatcher;             case DataSourceType.IA:                 return IA;             case DataSourceType.Sql:                 return Sql;             default:                 throw new NotImplementedException(ds.SelectedDataSourceType.Value.ToString());         }     } } 
like image 44
Jason Turan Avatar answered Sep 25 '22 05:09

Jason Turan