WPF: How to customize SelectionBoxItem in ComboBox WPF: How to customize SelectionBoxItem in ComboBox wpf wpf

WPF: How to customize SelectionBoxItem in ComboBox


I would do it like this:

<Window.Resources>  <DataTemplate x:Key="NormalItemTemplate" ...>    ...  </DataTemplate>  <DataTemplate x:Key="SelectionBoxTemplate" ...>    ...  </DataTemplate>  <DataTemplate x:Key="CombinedTemplate">    <ContentPresenter x:Name="Presenter"       Content="{Binding}"       ContentTemplate="{StaticResource NormalItemTemplate}" />    <DataTemplate.Triggers>      <DataTrigger        Binding="{Binding RelativeSource={RelativeSource FindAncestor,ComboBoxItem,1}}"        Value="{x:Null}">        <Setter TargetName="Presenter" Property="ContentTemplate"                Value="{StaticResource SelectionBoxTemplate}" />      </DataTrigger>    </DataTemplate.Triggers>  </DataTemplate></Window.Resources>...<ComboBox  ItemTemplate="{StaticResource CombinedTemplate}"  ItemsSource="..."  ... />

The reason this works is that CombinedTemplate normally just uses NormalItemTemplate to present its data, but if there is no ComboBoxItem ancestor it assumes it is in the selection box so it uses SelectionBoxTemplate.

Note that the three DataTemplates could be included in any level of ResourceDictionary (not just at the Window level) or even directly within the ComboBox, depending on your preference.


If I have this straight, you want a control that has something arbitrary displayed along with a drop-down button that displays a list of items with checkboxes next to them?

I wouldn't even bother trying to restyle a ComboBox to achieve this. The problem is that ComboBox is more specialized down a different path than what you need. If you look at the ComboBox ControlTemplate Example, you'll see that it simply uses a Popup control to display the list of possible values.

You can take pieces of that template as guidance to creating a UserControl that is easier to understand and better provides what you want. You'll even be able to add a SelectedItems property and such that ComboBox doesn't provide.

An example of what I mean by guidance: the Popup has an IsOpen property. In the control template, it's set to {TemplateBinding IsDropDownOpen}, which means that the ComboBox class has an IsDropDownOpen property that is changed in order to control the expand/collapse of the Popup.


Alexey Mitev's comment on Ray Burns' answer inspired me to write the following reasonably short utility class, which I now use in all my WPF projects:

public class ComboBoxItemTemplateSelector : DataTemplateSelector{    public List<DataTemplate> SelectedItemTemplates { get; } = new List<DataTemplate>();    public List<DataTemplate> DropDownItemTemplates { get; } = new List<DataTemplate>();    public override DataTemplate SelectTemplate(object item, DependencyObject container)    {        return GetVisualParent<ComboBoxItem>(container) == null            ? ChooseFrom(SelectedItemTemplates, item)            : ChooseFrom(DropDownItemTemplates, item);    }    private static DataTemplate ChooseFrom(IEnumerable<DataTemplate> templates, object item)    {        if (item == null)            return null;        var targetType = item.GetType();        return templates.FirstOrDefault(t => (t.DataType as Type) == targetType);    }    private static T GetVisualParent<T>(DependencyObject child) where T : Visual    {        while (child != null && !(child is T))            child = VisualTreeHelper.GetParent(child);        return child as T;    }}

With that in the toolbox, it's possible to write XAML like this:

<UserControl.Resources>     <DataTemplate x:Key="SelectedItemTemplateForInt" DataType="{x:Type system:Int32}">         <!-- ... -->     </DataTemplate>     <DataTemplate x:Key="SelectedItemTemplateForDouble" DataType="{x:Type system:Double}">         <!-- ... -->     </DataTemplate>     <DataTemplate x:Key="DropDownItemTemplateForInt" DataType="{x:Type system:Int32}">         <!-- ... -->     </DataTemplate>     <DataTemplate x:Key="DropDownItemTemplateForDouble" DataType="{x:Type system:Double}">         <!-- ... -->     </DataTemplate></UserControl.Resources><ComboBox>    <ComboBox.ItemTemplateSelector>        <local:ComboBoxItemTemplateSelector>            <local:ComboBoxItemTemplateSelector.SelectedItemTemplates>                <StaticResource ResourceKey="SelectedItemTemplateForInt" />                <StaticResource ResourceKey="SelectedItemTemplateForDouble" />            </local:ComboBoxItemTemplateSelector.SelectedItemTemplates>            <local:ComboBoxItemTemplateSelector.DropDownItemTemplates>                <StaticResource ResourceKey="DropDownItemTemplateForInt" />                <StaticResource ResourceKey="DropDownItemTemplateForDouble" />            </local:ComboBoxItemTemplateSelector.DropDownItemTemplates>        </local:ComboBoxItemTemplateSelector>    </ComboBox.ItemTemplateSelector></ComboBox>