Click here to Skip to main content
15,867,453 members
Articles / Desktop Programming / WPF

Using a different DataTemple when a WPF ComboBox is expanded

Rate me:
Please Sign up or sign in to vote.
5.00/5 (18 votes)
17 Dec 2009CPOL 73.4K   2.3K   39   7
Demonstrates overriding the DataTemplateSelector.SelectTemplate method.

ComboBoxExample

Introduction

This is a WPF combobox that displays one line when closed and multiple lines when expanded.

Using the Code

The first thing I did was create the data templates that control how the address is going be displayed. When it's collapsed, I just wanted to show the AddressName and AddressType on one line:

XML
<DataTemplate x:Key="AddressComboCollapsed" >
    <StackPanel Width="150" HorizontalAlignment="Stretch" >
        <DockPanel HorizontalAlignment="Stretch">
            <TextBlock Text="{Binding Path=AddressName}" 
                       DockPanel.Dock="Left" 
            />
            <TextBlock Text="{Binding Path=AddressType}" 
                       DockPanel.Dock="Right"
                       HorizontalAlignment="Right"
            />
        </DockPanel>
    </StackPanel>
</DataTemplate>

When it's expanded, I want to show the whole address and suppress AddressLine2 if it's blank:

XML
<DataTemplate x:Key="AddressComboExpanded" >
    <GroupBox BorderThickness = "1"
              Margin = "0,0,0,3"
              Width = "Auto "
              HorizontalAlignment = "Stretch"
              Header = "{Binding Path=AddressType}">
        <StackPanel Margin="3" 
                    HorizontalAlignment="Stretch"
                    MinWidth="250">
                <TextBlock Text = "{Binding Path=AddressName}"/>

            <TextBlock Text = "{Binding Path=AddressLine1}"
                       Name = "tbAddr1"
            />
            <TextBlock Text = "{Binding Path=AddressLine2}"
                       Name = "tbAddr2"
            />

            <!-- City, State, and ZIP display -->
            <StackPanel Orientation = "Horizontal">
                <TextBlock Text = "{Binding Path=City}" />
                <TextBlock Text="," Padding="0,0,5,0"/>
                <!-- Put a comma between city and state -->

                <TextBlock Text = "{Binding Path=State}" Padding="0,0,5,0" />
                <TextBlock Text = "{Binding Path=PostalCode}" />
            </StackPanel>
        </StackPanel>
    </GroupBox>

    <DataTemplate.Triggers>
        <!--If the "AddressLine2" portion of the address is blank, then
            HIDE it (no need to display an extra blank line)
            
            This only works is AddressLine2 = "", not if it's null
        -->
        <DataTrigger Binding = "{Binding Path=AddressLine2}" Value = "">
            <Setter TargetName = "tbAddr2" 
                    Property = "Visibility" 
                    Value = "Collapsed"
            />
        </DataTrigger>
    </DataTemplate.Triggers>
</DataTemplate>

The step was to create a AddressTemplateSelector class that inherits from System.Windows.Controls.DataTemplateSelector.DataTemplateSelector, and override the SelectTemplate method.

C#
public class AddressTemplateSelector : System.Windows.Controls.DataTemplateSelector
{
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        ContentPresenter presenter = (ContentPresenter)container;

        if (presenter.TemplatedParent is ComboBox)
        {
            return (DataTemplate)presenter.FindResource("AddressComboCollapsed");
        }
        else // Templated parent is ComboBoxItem
        {
            return (DataTemplate)presenter.FindResource("AddressComboExpanded");
        }
    }
}

After that, it's just a matter of importing the namespace of the DataTemplateSelector into the Window, merging the Resource Dictionary that contains the DataTemplates, and setting the ItemTemplateSelector of the ComboBox.

XML
<ComboBox Height="30" Width="200"
            ItemsSource="{Binding Path=Addresses}">
    <ComboBox.ItemTemplateSelector>
        <dt:AddressTemplateSelector/>
    </ComboBox.ItemTemplateSelector>
</ComboBox>

Points of Interest

If you look closely at the templates, you'll notice that the expanded template is wider than both the combobox and the collapsed template. This allows you to have the list be wider than the original combobox. That'll be a nice feature when I move on to the state selection combo (display only StateCode, but show StateCode + StateName when expanded).

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
United States United States
I’m a Software Engineer at Microsoft working on the Azure Portal. Before that I spent about 20 years developed various business applications at a number of different companies. I have a passion for writing clean, scalable code and sharing what I’ve learned with others.

I also help run the Casco Bay .Net User Group

Comments and Discussions

 
QuestionHi, Pin
Member 1479047516-Apr-20 5:21
Member 1479047516-Apr-20 5:21 
QuestionPreload combo selected value Pin
alag2020-Aug-12 6:38
alag2020-Aug-12 6:38 
AnswerRe: Preload combo selected value Pin
Stirbelwurm24-Aug-14 23:01
Stirbelwurm24-Aug-14 23:01 
GeneralMy vote of 5 Pin
twf195616-Feb-12 10:51
twf195616-Feb-12 10:51 
GeneralMy vote of 5 Pin
John Adams22-Oct-10 5:45
John Adams22-Oct-10 5:45 
Generalgood article, thx Pin
Jacky.ShuaiWu27-May-10 19:59
Jacky.ShuaiWu27-May-10 19:59 
GeneralThank you. Pin
ramfish22-Dec-09 10:50
ramfish22-Dec-09 10:50 
This is great, thank you. I've spent about 4hrs searching how to 'style' the dropdown list, and got totally lost in the itemcontainerstyle / blend / xaml / content control etc etc.. This is nice and simple and nicely seperates the different elements.

Cheers.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.