Sometimes even simple things can be confusing. Especially if you don’t encounter them every day. The funniest thing is if you’ve already solved this problem and successfully forgot about it after some time.

With this note I want to create a reminder for myself on how to use DataTemplateSelector in ItemsControl properly.

The steps to implement the support for DataTemplateSelector:

  • Implement the class that inherits DataTemplateSelector
    • Add properties to store data templates
    • Override two Core methods with template selection logic
  • Add data templates to the resources
  • Add the template selector to the resources (and set data templates)
  • Set ItemTemplateSelector property of ItemsControl

Suppose, we need to create a template selector to select a template for the menu item: text item or separator. The following code shows the simple data template selector:

class MenuItemTemplateSelector : DataTemplateSelector
{
    public DataTemplate ItemTemplate { get; set; }

    public DataTemplate SeparatorTemplate { get; set; }

    // This method isn't invoked. As a result, only the result of .ToString() is shown
    protected override DataTemplate SelectTemplateCore(object item)
    {
        if (item is IconMenuItem menuItem)
        {
            return menuItem.Text == "-"
                ? SeparatorTemplate
                : ItemTemplate;
        }
        else
        {
            return null;
        }
    }

    // So we also need to implement this method. It solves the problem and the template is selected properly
    protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
    {
        return SelectTemplateCore(item);
    }
}

In the documentation only the first method is implemented. But in this case it’s not called (or is called in special cases that I haven’t found). So we need to implement the second method to make the template selection work.

Otherwise, everything works as described in the documentation.

And the XAML file is the following:

<Grid.Resources>
    <DataTemplate x:DataType="root:IconMenuItem" x:Key="SeparatorTemplate">
        <MenuFlyoutSeparator IsTabStop="False" />
    </DataTemplate>

    <DataTemplate x:DataType="root:IconMenuItem" x:Key="ItemTemplate">
        <MenuFlyoutItem
            Padding="12, 6"
            Text="{Binding Text, Mode=OneWay}" 
            Command="{Binding Command, Mode=OneWay}"
            Click="MenuFlyoutItem_Click" />
    </DataTemplate>

    <local:MenuItemTemplateSelector x:Key="TemplateSelector"
        ItemTemplate="{StaticResource ItemTemplate}"
        SeparatorTemplate="{StaticResource SeparatorTemplate}" />
</Grid.Resources>

<ItemsControl Background="Transparent" Padding="5"
    ItemsSource="{Binding MenuItems, Mode=OneWay}"
    ItemTemplateSelector="{StaticResource TemplateSelector}">
</ItemsControl>