1

I have ContentControl and my DataTemplateSelector support also null value.

<ContentControl Content="{x:Bind CurrentItem, Mode=OneWay}">
    <ContentControl.DataTemplateSelector>
        <my:DataTemplateSelector>
            <my:DataTemplateSelector.NullTemplate>
                <DataTemplate>
                    <Border Background="Red" />
                </DataTemplate>
            </my:DataTemplateSelector.NullTemplate>
            <my:DataTemplateSelector.CustomTemplate1>
                <DataTemplate>
                    <Border Background="Green" />
                </DataTemplate>
            </my:DataTemplateSelector.CustomTemplate1>
            <my:DataTemplateSelector.CustomTemplate2>
                <DataTemplate>
                    <Border Background="Blue" />
                </DataTemplate>
            </my:DataTemplateSelector.CustomTemplate2>
        </my:DataTemplateSelector>
    </ContentControl.DataTemplateSelector>                
</ContentControl>

The problem is that when CurrentItem changes to null, it doesn't call SelectTemplateCore method in DataTemplateSelector. Actually NullTemplate is select only when control is loaded first time and CurrentItem is null.

I can replace null value with dummy object but it's much more difficult to deal with this problem. I have found this solution but it's only for WPF (UWP doesn't have Style.Triggers)

Community
  • 1
  • 1
Posix
  • 300
  • 3
  • 14

1 Answers1

0

I'm not sure what is your ContentControl.DataTemplateSelector, I suppose it is the ContentControl.ContentTemplateSelector in UWP.

The problem is that when CurrentItem changes to null, it doesn't call SelectTemplateCore method in DataTemplateSelector. Actually NullTemplate is select only when control is loaded first time and CurrentItem is null.

Yes, you're right about this. When you set CurrentItem to null later, the TemplateSelector will not run into the DataTemplateSelector again. What you need is to create a nullable property for CurrentItem. For example:

<Page.Resources>
    <DataTemplate x:Key="NullTemplate">
        <Border Background="Red" Height="300" Width="300">
            <TextBlock Text="{Binding TemplateName}" />
        </Border>
    </DataTemplate>
    <DataTemplate x:Key="CustomTemplate1">
        <Border Background="Green" Height="300" Width="300">
            <TextBlock Text="{Binding TemplateName}" />
        </Border>
    </DataTemplate>
    <DataTemplate x:Key="CustomTemplate2">
        <Border Background="Blue" Height="300" Width="300">
            <TextBlock Text="{Binding TemplateName}" />
        </Border>
    </DataTemplate>
    <local:MyDataTemplateSelector x:Key="MyDataTemplateSelector"
                                  NullTemplate="{StaticResource NullTemplate}"
                                  CustomTemplate1="{StaticResource CustomTemplate1}"
                                  CustomTemplate2="{StaticResource CustomTemplate2}" />
</Page.Resources>

<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <ComboBox x:Name="combo" SelectionChanged="combo_SelectionChanged">
        <ComboBoxItem Content="NullTemplate" />
        <ComboBoxItem Content="CustomTemplate1" />
        <ComboBoxItem Content="CustomTemplate2" />
        <ComboBoxItem Content="SetCurrentItemToNull" />
        <ComboBoxItem Content="SetCurrentItemPropertyToNull" />
    </ComboBox>
    <ContentControl Content="{x:Bind CurrentItem, Mode=OneWay}" Margin="0,10"
                    ContentTemplateSelector="{StaticResource MyDataTemplateSelector}" />
</StackPanel>

code behind:

private ContentControlDataModel _CurrentItem;

public ContentControlDataModel CurrentItem
{
    get { return _CurrentItem; }
    set
    {
        if (value != _CurrentItem)
        {
            _CurrentItem = value;
            OnPropertyChanged();
        }
    }
}

public event PropertyChangedEventHandler PropertyChanged;

private void OnPropertyChanged([CallerMemberName]string propertyName = "")
{
    if (this.PropertyChanged != null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

private void combo_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    var item = combo.SelectedItem as ComboBoxItem;
    switch (item.Content.ToString())
    {
        case "NullTemplate":
            CurrentItem = new ContentControlDataModel { Template = null, TemplateName = "NullTemplate" };
            break;

        case "CustomTemplate1":
            CurrentItem = new ContentControlDataModel { Template = true, TemplateName = "CustomTemplate1" };
            break;

        case "CustomTemplate2":
            CurrentItem = new ContentControlDataModel { Template = false, TemplateName = "CustomTemplate2" };
            break;

        case "SetCurrentItemToNull":
            CurrentItem = null;
            break;

        case "SetCurrentItemPropertyToNull":
            CurrentItem = new ContentControlDataModel { Template = null, TemplateName = null };
            break;

    }
}

ContentControlDataModel is like this:

public class ContentControlDataModel
{
    public bool? Template { get; set; } //nullable property
    public string TemplateName { get; set; }
}

and the MyDataTemplateSelector:

public class MyDataTemplateSelector : DataTemplateSelector
{
    public DataTemplate NullTemplate { get; set; }
    public DataTemplate CustomTemplate1 { get; set; }
    public DataTemplate CustomTemplate2 { get; set; }

    protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
    {
        var model = item as ContentControlDataModel;
        if (model == null || model.Template == null)
            return this.NullTemplate;
        else
        {
            return (bool)model.Template ? this.CustomTemplate1 : this.CustomTemplate2;
        }
    }
}

Rendering Image:

enter image description here

You can check the differences by selecting different items of ComboBox.

Grace Feng
  • 16,564
  • 2
  • 22
  • 45