Different ComboBox ItemTemplate for dropdown

Let’s say we want our ComboBox to display one thing for the selected item and another thing in the dropdown.

It sounds easy enough but the problem is that there is only one ItemTemplate. So how do we specify two different DataTemplates? This is a very common problem and it can be solved in a number of ways.

ItemTemplateSelector

An easy way, which I like, is to use ItemTemplateSelector instead of ItemTemplate. All we need is a new class, ComboBoxItemTemplateSelector, that derives from DataTemplateSelector and defines the two properties SelectedTemplate and DropDownTemplate. So instead of this..

<ComboBox ItemsSource="{Binding MyDataList}">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding ID}"/>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

..we specify two DataTemplates like this

<ComboBox ItemsSource="{Binding MyDataList}">
    <ComboBox.ItemTemplateSelector>
        <ts:ComboBoxItemTemplateSelector>
            <ts:ComboBoxItemTemplateSelector.SelectedTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding ID}"/>
                </DataTemplate>
            </ts:ComboBoxItemTemplateSelector.SelectedTemplate>
            <ts:ComboBoxItemTemplateSelector.DropDownTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Details}"/>
                </DataTemplate>
            </ts:ComboBoxItemTemplateSelector.DropDownTemplate>
        </ts:ComboBoxItemTemplateSelector>
    </ComboBox.ItemTemplateSelector>
</ComboBox>

ComboBoxItemTemplateSelector

So how does the ComboBoxItemTemplateSelector know if it should return the SelectedTemplate or the DropDownTemplate? Only the items in the dropdown are wrapped in a ComboBoxItem so if we find a ComboBoxItem parent in the visual tree, we’re dealing with the dropdown.

public class ComboBoxItemTemplateSelector : DataTemplateSelector
{
    public DataTemplate SelectedTemplate { get; set; }
    public DataTemplate DropDownTemplate { get; set; }

    public override DataTemplate SelectTemplate(object item,
                                                DependencyObject container)
    {
        ComboBoxItem comboBoxItem = container.GetVisualParent<ComboBoxItem>();
        if (comboBoxItem == null)
        {
            return SelectedTemplate;
        }
        return DropDownTemplate;
    }
}

Shorter version with attached properties

It can also be shortened a bit (if this is going to be used many times in a project for example) by using attached properties.
I would like to call this one ComboBoxItemTemplateSelector as well but since I’m including them both in the demo project below I had to come up with another name 🙂

<ComboBox ItemsSource="{Binding MyDataList}"
          ItemTemplateSelector="{StaticResource ComboBoxItemTemplateChooser}">
    <cbp:ComboBoxItemTemplateChooser.SelectedTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding ID}"/>
        </DataTemplate>
    </cbp:ComboBoxItemTemplateChooser.SelectedTemplate>
    <cbp:ComboBoxItemTemplateChooser.DropDownTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Details}"/>
        </DataTemplate>
    </cbp:ComboBoxItemTemplateChooser.DropDownTemplate>
</ComboBox>

And in SelectTemplate we do the same thing but instead of returning SelectedTemplate/DropDownTemplate we find the parent ComboBox and return the attached property SelectedTemplate/DropDownTemplate.

public class ComboBoxItemTemplateChooser : DataTemplateSelector
{
    #region SelectedTemplate..
    #region DropDownTemplate..

    public override DataTemplate SelectTemplate(object item,
                                                DependencyObject container)
    {
        ComboBox comboBox = null;
        ComboBoxItem comboBoxItem = container.GetVisualParent<ComboBoxItem>();
        if (comboBoxItem == null)
        {
            comboBox = container.GetVisualParent<ComboBox>();
            return ComboBoxItemTemplateChooser.GetSelectedTemplate(comboBox);
        }
        comboBox =
            ComboBox.ItemsControlFromItemContainer(comboBoxItem) as ComboBox;
        return ComboBoxItemTemplateChooser.GetDropDownTemplate(comboBox);
    }
}

A small demo project with examples of both methods can be downloaded below.
Download demo project here.

Hope you find it useful! 🙂
/Fredrik

Advertisements

4 Responses to Different ComboBox ItemTemplate for dropdown

  1. Thomas Phaneuf says:

    Nicely done! Thank you!

  2. Amber says:

    Thank you. you have saved the day for me 🙂

  3. Amber says:

    Thank you.

  4. hassan says:

    Thank you !!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: