ContentControl.ContentTemplateSelector dynamically select template
Asked Answered
L

1

8

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:

enter image description here

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);
    }
}
Locate answered 9/12, 2013 at 10:21 Comment(2)
Have you implemented the 'INotifyPropertyChanged` interface in your view model and for the Items property?Hitchhike
I use mvvmlight. The class MyViewModel inherits from ViewModelBase. ViewModelBase : ObservableObject : INotifyPropertyChanged.Locate
U
15

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>
Unsaid answered 9/12, 2013 at 12:49 Comment(3)
Thanks, this way work well. But I still dont know why it dont work when I manually call RaisePropertyChanged(ItemsPropertyName) in this case: Now Items.Count is 1, and I delete the only one item and call RaisePropertyChanged(ItemsPropertyName).Locate
Are you sure value of ItemsPropertyName is the string value Items and not null. You didn't provide the property declaration for that property, so cannot comment on that further.Unsaid
@Locate Check the capitalization of first letter.Unsaid

© 2022 - 2024 — McMap. All rights reserved.