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.