ContentControl.ContentTemplateSelector dynamically select template
c#, contenttemplateselector, mvvm, wpf
Solution
`ContentControl` will listen only for `PropertyChanged` events and not for `CollectionChanged` event. You'll need to use either an `ItemsControl` or any of its other versions like `ListView` for this behavior.
As a workaround, you can create a `Style` for the `ContentControl` and instead of `TemplateSelector`, define a `DataTrigger` on `Items.Count` and set the `ContentTemplate` accordingly. Something like,
<ContentControl Content="{Binding Items}">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="ContentTemplate" Value="{StaticResource DefaultDataTemplate}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Items}" Value="{x:Null}">
<Setter Property="ContentTemplate" Value="{StaticResource NullItemDataTemplate}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=Items.Count}" Value="0">
<Setter Property="ContentTemplate" Value="{StaticResource NullItemDataTemplate}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
Problem
I set a ContentControl in the right of Window, and set Content binding Items (it's type is ObservableCollection). Now I want to achieve it: if there are no item, ContentControl select first DataTemplate, and add a item into items, ContentControl will select second DataTemplate to display some info. Like this: The problem is when I add one item into items, ContentControl didnot update and change DataTemplate, I have a try to set mode, UpdateSourceTrigger, etc., but failed. In ViewModel, after delete a item, I use this statements, it will work well <1>: ``` private void ExecuteDeleteClientCommand() { ... if (DeleteClient(item)) { ObservableCollection<MyViewModel> tmp = TabItems; TabItems = null; TabItems = tmp; } } ``` . ``` <ContentControl ContentTemplateSelector="{StaticResource MyDataTemplateSelector}" Content="{Binding Items}"/> ``` . ``` public class SingleClientDataTemplateSelector : DataTemplateSelector { public override DataTemplate SelectTemplate(object item, DependencyObject container) { ObservableCollection<MyViewModel> obj = item as ObservableCollection<MyViewModel>; if (null == obj || 0 == obj.Count) { return App.Current.FindResource("NullItemDataTemplate") as DataTemplate; } return App.Current.FindResource("DefaultDataTemplate") as DataTemplate; } } ``` Edited: use this way is also failed after delete one item: ``` RaisePropertyChanging(ItemsPropertyName); RaisePropertyChanged(ItemsPropertyName); ``` but I wonder why it work well with <1>. Edited2 It's the delcaration: ``` public const string ItemsPropertyName = "Items"; private ObservableCollection<MyViewModel> items = new ObservableCollection<MyViewModel>(); public ObservableCollection<SingleClientDetailViewModel> TabItems { get { return items; } set { if (items == value) { return;} RaisePropertyChanging(ItemsPropertyName); items = value; RaisePropertyChanged(ItemsPropertyName); } } ```