#1,015 – Typing Text to Select an Item in a ComboBox, Part III

You set the TextSearch.TextPath property on a ComboBox to refer to the property on the bound object that contains the text that you can type in order to select an item.

You can change the ComboBox so that the text that you enter to select an item is visible as you enter the text.  To do this, you set the IsEditable property to true.

        <ComboBox ItemsSource="{Binding ActorList}" Margin="20"
                  IsEditable="True"
                  SelectedItem="{Binding SelectedActor}"
                  TextSearch.TextPath="LastName">
            <ComboBox.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <Image Source="{Binding Image}" Height="100"/>
                                <StackPanel Margin="10,0">
                                    <TextBlock Text="{Binding FullName}" FontWeight="Bold" />
                                    <TextBlock Text="{Binding Dates}"/>
                                    <TextBlock Text="{Binding KnownFor}" FontStyle="Italic"/>
                                </StackPanel>
                            </StackPanel>
                        </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>

        <Label Content="{Binding SelectedActor.NameAndDates}"/>

In this example, we can now type the actor’s last name in order to change the selected item.  We can demonstrate this by binding a Label to the selector item (actor).  Notice that the selected item changes as we enter text.
1015-001

#1,014 – Typing Text to Select an Item in a ComboBox, Part II

If a ComboBox has focus, you can normally just start typing text in order to select an item.  If the DisplayMemberPath property is set, you can enter text that matches the property on the bound object specified by DisplayMemberPath.  If you are using an item template to set content for each item, rather than DisplayMemberPath, you can specify the property used when typing text by setting the TextSearch.TextPath property.

In the example below, we set TextSearch.TextPath to LastName, which is a property of the Actor object that each item is bound to.  The user can then just type the actor’s last name in order to select that actor within the ComboBox.

        <ComboBox ItemsSource="{Binding ActorList}" Margin="20"
                  SelectedItem="{Binding SelectedActor}"
                  TextSearch.TextPath="LastName">
            <ComboBox.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <Image Source="{Binding Image}" Height="100"/>
                                <StackPanel Margin="10,0">
                                    <TextBlock Text="{Binding FullName}" FontWeight="Bold" />
                                    <TextBlock Text="{Binding Dates}"/>
                                    <TextBlock Text="{Binding KnownFor}" FontStyle="Italic"/>
                                </StackPanel>
                            </StackPanel>
                        </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>

1014-001

#1,013 – Typing Text to Select an Item in a ComboBox

If a ComboBox has focus, you can just type some text in order to select an item.  By default, the text that you enter will be matched against the property specified by the DisplayMemberPath property, or by the value of the bound object’s ToString method, if DisplayMemberPath is not specified.

In the example below, we don’t specify DisplayMemberPath, but instead specify an ItemTemplate.  If the ComboBox has focus and we start typing, the ToString method of the underlying Actor object is used to determine the object to navigate to.

        <ComboBox ItemsSource="{Binding ActorList}" Margin="20"
                  SelectedItem="{Binding SelectedActor}">
            <ComboBox.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <Image Source="{Binding Image}" Height="100"/>
                                <StackPanel Margin="10,0">
                                    <TextBlock Text="{Binding FullName}" FontWeight="Bold" />
                                    <TextBlock Text="{Binding Dates}"/>
                                    <TextBlock Text="{Binding KnownFor}" FontStyle="Italic"/>
                                </StackPanel>
                            </StackPanel>
                        </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>

If we’ve defined Actor.ToString() to return the actor’s name in a LastName, FirstName format, we can then navigate to an actor by typing their last name.  For example, entering “L” might select Hedy Lamarr.

1013-001

#1,012 – Using a Different Data Template for the Face of a ComboBox

When you define a data template to use as the item template for a ComboBox, this item template is used to render each item in the dropdown list when it appears.  The same item template is used to display the currently selected item on the face of the ComboBox.

1012-001

You can define a different template for the face of the ComboBox using a DataTemplateSelector.  You start by defining a data template selector that allows setting one of two templates and can determine whether the parent of the current item is the ComboBox itself (face of button) or a ComboBoxItem (dropdown).

    public class ComboBoxItemTemplateSelector : DataTemplateSelector
    {
        // Can set both templates from XAML
        public DataTemplate SelectedItemTemplate { get; set; }
        public DataTemplate ItemTemplate { get; set; }

        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            bool selected = false;

            // container is the ContentPresenter
            FrameworkElement fe = container as FrameworkElement;
            if (fe != null)
            {
                DependencyObject parent = fe.TemplatedParent;
                if (parent != null)
                {
                    ComboBox cbo = parent as ComboBox;
                    if (cbo != null)
                        selected = true;
                }
            }

            if (selected)
                return SelectedItemTemplate;
            else
                return ItemTemplate;
        }
    }

You can now define two different templates in your XAML.

        <ComboBox ItemsSource="{Binding ActorList}" Margin="20"
                  SelectedItem="{Binding SelectedActor}">
            <ComboBox.ItemTemplateSelector>
                <local:ComboBoxItemTemplateSelector>
                    <local:ComboBoxItemTemplateSelector.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <Image Source="{Binding Image}" Height="100"/>
                                <StackPanel Margin="10,0">
                                    <TextBlock Text="{Binding FullName}" FontWeight="Bold" />
                                    <TextBlock Text="{Binding Dates}"/>
                                    <TextBlock Text="{Binding KnownFor}" FontStyle="Italic"/>
                                </StackPanel>
                            </StackPanel>
                        </DataTemplate>
                    </local:ComboBoxItemTemplateSelector.ItemTemplate>
                    <local:ComboBoxItemTemplateSelector.SelectedItemTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <Image Source="{Binding Image}" Height="40" Margin="5,0"/>
                                <TextBlock Text="{Binding FullName}"/>
                            </StackPanel>
                        </DataTemplate>
                    </local:ComboBoxItemTemplateSelector.SelectedItemTemplate>
                </local:ComboBoxItemTemplateSelector>
            </ComboBox.ItemTemplateSelector>
        </ComboBox>

We now have a different layout on the face of the ComboBox, showing the currently selected item.

1012-002

#1,011 – ComboBox Data Binding Basics, Part III

To display the items in a ComboBox using something more than a simple string, you set the ItemTemplate of the ComboBox to define the layout of each item.  When you set the ItemTemplate, you don’t set the DisplayMemberPath property.  DisplayMemberPath defines the template for each item in the ComboBox to be a TextBlock that displays a single string.

Below, we set an item template for a ComboBox that binds to a collection of Actor objects so that we display an image and some information about the actor, for each item.

        <ComboBox ItemsSource="{Binding ActorList}" Margin="20"
                  SelectedItem="{Binding SelectedActor}">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Image Source="{Binding Image}" Height="100"/>
                        <StackPanel Margin="10,0">
                            <TextBlock Text="{Binding FullName}" FontWeight="Bold" />
                            <TextBlock Text="{Binding Dates}"/>
                            <TextBlock Text="{Binding KnownFor}" FontStyle="Italic"/>
                        </StackPanel>
                    </StackPanel>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>
        <Label Content="{Binding SelectedActor.NameAndDates}"/>

As we select an item, notice that the ComboBox changes size, so that the surface can show the entire item.

1011-001

1011-002

#1,010 – ComboBox Data Binding Basics, Part II

When using data binding, you specify the collection of items to fill the ComboBox by setting the ItemsSource property.

You can also bind the currently selected item in the ComboBox to an instance of an object in code.  You do this by binding the SelectedItem property to a property in your code that represents an instance of the appropriate type.  When the user selects an item in the ComboBox, the corresponding object is updated to refer to the selected object.

Assume that we have the following in our code behind:

  • Actor class, representing an actor
  • ActorList property, which is an ObservableCollection<Actor>
  • SelectedActor property, of type Actor

In the example below, we bind the ComboBox to the list of actors and the currently selected actor to the SelectedActor property.  As we select an actor, the Label updates, since it also binds to SelectedActor.

        <ComboBox ItemsSource="{Binding ActorList}" Margin="20"
                  DisplayMemberPath="FullName"
                  SelectedItem="{Binding SelectedActor}"/>
        <Label Content="{Binding SelectedActor.NameAndDates}"/>

1010-001
1010-002

#1,009 – ComboBox Data Binding Basics, Part I

As with a ListBox, you can use data binding to load and manage the items displayed in a ComboBox control.

You set the ItemsSource property of the ComboBox to a collection that implements the IEnumerable interface.  The collection bound to can contain any type of object.

If you want the ComboBox to display simple strings, you can set the DisplayMemberPath property to the string-typed property of a bound object  that should be used to get the display string for each item.

        <ComboBox ItemsSource="{Binding ActorList}" Margin="20"
                  DisplayMemberPath="FullName"/>

1009-001