WPF: Reapply DataTemplateSelector when a certain value changes
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>
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()); } }}
Returning back to your original solution and the problem of "the template selector doesn't get reapplied": you can refresh your view like that
CollectionViewSource.GetDefaultView(YourItemsControl.ItemsSource).Refresh();
where for brevity sake your ItemsControl is referenced by its name ("YourItemsControl") added to your XAML:
<ItemsControl x:Name="YourItemsControl" ItemsSource="{Binding Path=Groups}" ItemTemplateSelector="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=ListTemplateSelector}"/>
The only problem may be how to choose right place in your project for this refresh instruction. It could go into a view code-behind, or, if your IsLeaf is a DP, the right place would be a dependency-property-changed callback.