When ItemsControl.ItemContainerStyle is specified together with ItemsControl.ItemTemplateSelector, the later is ignored

WPF-Learner 106 Reputation points
2021-11-29T18:26:04.367+00:00

I have a ComboBox in which I specify the ItemTemplateSelector property.

It works properly.

Once I specify the ItemContainerStyle property for the ComboBox too (in addition to the specified ItemTemplateSelector property), the ItemTemplateSelector is ignored (the breakpoint in

public override DataTemplate SelectTemplate

is not hit). What is the reason for that?

It's important to mention the I override the ControlTemplate for the ComboBoxItem in that ItemContainerStyle via

 <Setter Property="Control.Template">

but it is the default WPF template of ComboBoxItem (I've only changed colors).

Once I specify in this default template of ComboBoxItem:

ContentTemplateSelector="{TemplateBinding ContentControl.ContentTemplateSelector}"

for the ContentPresenter element within the default control template, the ItemTemplateSelector starts working again. But how can it be that this

ContentTemplateSelector="{TemplateBinding ContentControl.ContentTemplateSelector}"

it not specified in the default WPF ComboBoxItem Control template? How does it work without it when I don't specify the ItemContainerStyle for the combobox itself (I mean, without me specifying it, the ComboBoxItem has the default template that does not consist of this line)?

EDIT: I've managed to prepare a short POC in which this issue is reproduced - I have only 3 classes in this POC:

MainWindow.xaml

<Window x:Class="WpfApp4.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp4"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
<Window.Resources>

        <Style x:Key="ComboBoxItemStyle" TargetType="{x:Type ComboBoxItem}">
            <Setter Property="UIElement.SnapsToDevicePixels"
            Value="True" />
            <Setter Property="Control.Padding"
            Value="4,1" />
            <Setter Property="Control.HorizontalContentAlignment">
                <Setter.Value>
                    <Binding Path="HorizontalContentAlignment"
                     RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=ItemsControl, AncestorLevel=1}" />
                </Setter.Value>
            </Setter>
            <Setter Property="Control.VerticalContentAlignment">
                <Setter.Value>
                    <Binding Path="VerticalContentAlignment"
                     RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=ItemsControl, AncestorLevel=1}" />
                </Setter.Value>
            </Setter>
            <Setter Property="Panel.Background"
            Value="#00FFFFFF" />
            <Setter Property="Border.BorderBrush"
            Value="#00FFFFFF" />
            <Setter Property="Border.BorderThickness"
            Value="1" />
            <Setter Property="FrameworkElement.FocusVisualStyle">
                <Setter.Value>
                    <Style TargetType="{x:Type IFrameworkInputElement}">
                        <Setter Property="Control.Template">
                            <Setter.Value>
                                <ControlTemplate>
                                    <Rectangle Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"
                                       StrokeThickness="1"
                                       StrokeDashArray="1 2"
                                       Margin="2"
                                       SnapsToDevicePixels="True" />
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </Setter.Value>
            </Setter>
            <Setter Property="Control.Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ComboBoxItem}">
                        <Border BorderThickness="{TemplateBinding Border.BorderThickness}"
                        Padding="{TemplateBinding Control.Padding}"
                        BorderBrush="{TemplateBinding Border.BorderBrush}"
                        Background="{TemplateBinding Panel.Background}"
                        Name="Bd"
                        SnapsToDevicePixels="True">
                            <ContentPresenter Content="{TemplateBinding ContentControl.Content}"
                                      ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}"
                                      ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}"
                                      HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}"
                                      VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}"
                                      SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="UIElement.IsEnabled"
                             Value="False">
                                <Setter Property="TextElement.Foreground"
                                TargetName="Bd"
                                Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
                            </Trigger>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="Selector.IsSelected"
                                       Value="False" />
                                    <Condition Property="UIElement.IsMouseOver"
                                       Value="True" />
                                    <Condition Property="UIElement.IsKeyboardFocused"
                                       Value="False" />
                                </MultiTrigger.Conditions>
                                <Setter Property="Panel.Background"
                                TargetName="Bd"
                                Value="#1F26A0DA" />
                                <Setter Property="Border.BorderBrush"
                                TargetName="Bd"
                                Value="#A826A0DA" />
                            </MultiTrigger>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="Selector.IsSelected"
                                       Value="True" />
                                    <Condition Property="UIElement.IsMouseOver"
                                       Value="False" />
                                    <Condition Property="UIElement.IsKeyboardFocused"
                                       Value="True" />
                                </MultiTrigger.Conditions>
                                <Setter Property="Panel.Background"
                                TargetName="Bd"
                                Value="#3D26A0DA" />
                                <Setter Property="Border.BorderBrush"
                                TargetName="Bd"
                                Value="#26A0DA" />
                            </MultiTrigger>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="Selector.IsSelected"
                                       Value="True" />
                                    <Condition Property="UIElement.IsMouseOver"
                                       Value="True" />
                                </MultiTrigger.Conditions>
                                <Setter Property="Panel.Background"
                                TargetName="Bd"
                                Value="#2E0080FF" />
                                <Setter Property="Border.BorderBrush"
                                TargetName="Bd"
                                Value="#99006CD9" />
                            </MultiTrigger>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="Selector.IsSelected"
                                       Value="True" />
                                    <Condition Property="UIElement.IsMouseOver"
                                       Value="False" />
                                    <Condition Property="UIElement.IsKeyboardFocused"
                                       Value="False" />
                                </MultiTrigger.Conditions>
                                <Setter Property="Panel.Background"
                                TargetName="Bd"
                                Value="#3DDADADA" />
                                <Setter Property="Border.BorderBrush"
                                TargetName="Bd"
                                Value="#DADADA" />
                            </MultiTrigger>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="Selector.IsSelected"
                                       Value="False" />
                                    <Condition Property="UIElement.IsMouseOver"
                                       Value="False" />
                                    <Condition Property="UIElement.IsKeyboardFocused"
                                       Value="True" />
                                </MultiTrigger.Conditions>
                                <Setter Property="Border.BorderBrush"
                                TargetName="Bd"
                                Value="#26A0DA" />
                            </MultiTrigger>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="Selector.IsSelected"
                                       Value="False" />
                                    <Condition Property="UIElement.IsMouseOver"
                                       Value="True" />
                                    <Condition Property="UIElement.IsKeyboardFocused"
                                       Value="True" />
                                </MultiTrigger.Conditions>
                                <Setter Property="Panel.Background"
                                TargetName="Bd"
                                Value="#5426A0DA" />
                                <Setter Property="Border.BorderBrush"
                                TargetName="Bd"
                                Value="#26A0DA" />
                            </MultiTrigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>





        <DataTemplate x:Key="SelectedItemTemplate">
        <TextBlock Text="{Binding}" Background="Yellow"></TextBlock>
    </DataTemplate>

    <DataTemplate x:Key="DropdownItemTemplate">
        <TextBlock Text="{Binding}" Background="Red"></TextBlock>
        </DataTemplate>

        <local:TemplateSelector x:Key="TemplateSelector" SelectedTemplate="{StaticResource SelectedItemTemplate}"
                            ListItemTemplate="{StaticResource DropdownItemTemplate}" />
    </Window.Resources>
    <Grid>

        <ComboBox Height="80" Width="120" ItemTemplateSelector="{StaticResource TemplateSelector}" x:Name="TestComboBox" SelectedIndex="0" ItemsSource="{Binding Items}" ItemContainerStyle="{StaticResource ComboBoxItemStyle}"/>
    </Grid>
</Window>

MainWindow.xaml.cs:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApp4
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;
            this.Items = new ObservableCollection<string>() {"D1", "D2", "D3"};
        }

        public ObservableCollection<string> Items { get; set; }
    }
}

TemplateSelector:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace WpfApp4
{


    public class TemplateSelector : DataTemplateSelector
    {

        public DataTemplate SelectedTemplate { get; set; }


        public DataTemplate ListItemTemplate { get; set; }

        public override DataTemplate SelectTemplate(object serviceModel, DependencyObject container)
        {
            var itemControl = container;

            while (itemControl != null && !(itemControl is ComboBoxItem || itemControl is ComboBox))
                itemControl = VisualTreeHelper.GetParent(itemControl);

            return itemControl is ComboBoxItem ? ListItemTemplate : SelectedTemplate;
        }
    }
}

With the current POC code, the DropdownItemTemplate DataTemplate is ignored (I only get there once with the ContentPresenter of the ComboBox itself, but not the actual ComboBoxItems)

Once I remove the

ItemContainerStyle="{StaticResource ComboBoxItemStyle}"

from the ComboBox, it all works perfectly,

public override DataTemplate SelectTemplate

is hit both for the ComboBox itself and also for its ComboBoxItems.

I wonder why adding this ItemContainerStyle property makes the TemplateSelector to stop working properly.

Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,671 questions
{count} votes

Accepted answer
  1. Hui Liu-MSFT 38,251 Reputation points Microsoft Vendor
    2021-12-07T07:48:21.72+00:00

    If ItemContainerStyle is defined, we need to use ContentTemplateSelector in ContentPresenter with DataTemplateSelector.
    According to the display logic of ContentPresenter

    If the ContentTemplateSelector property on the ContentPresenter is set, the ContentPresenter applies the appropriate DataTemplate to the Content property and the resulting UIElement and its child elements, if any, are displayed.

    ContentPresenter.ContentTemplateSelector Property

    Gets or sets the DataTemplateSelector, which allows the application writer to provide custom logic for choosing the template that is used to display the content of the control.


    If the response is helpful, please click "Accept Answer" and upvote it.
     Note: Please follow the steps in our [documentation][5] to enable e-mail notifications if you want to receive the related email notification for this thread. 

    [5]: https://learn.microsoft.com/en-us/answers/articles/67444/email-notifications.html

    0 comments No comments

0 additional answers

Sort by: Most helpful