Sep 28, 2005

How to bind the items of a ComboBox (and get its ComboBoxItems)

4BindToComboBox

Binding the items of a ComboBox is pretty much the same as binding the items of a ListBox:

    <Window.Resources>
        <local:GreekGods x:Key="greekGods"/>
    
        <DataTemplate x:Key="itemTemplate">
            <TextBlock Text="{Binding Path=Name}" />
        </DataTemplate>
    </Window.Resources>

    <ComboBox ItemsSource="{StaticResource greekGods}" ItemTemplate="{StaticResource itemTemplate}" Width="200" Name="comboBox"/>

The reason for this similarity is that both ComboBox and ListBox derive from ItemsControl, and ItemsSource and ItemTemplate are properties on ItemsControl.

If you read my previous post about how to get a ListBoxItem from a data bound ListBox, you’re probably thinking that you don’t need to keep reading to know how to do the same thing for a ComboBox. There is a little trick that you should be aware of, though.

If you use similar code to the solution of my previous post, you will notice that the ComboBoxItems are null:

    GreekGod greekGod = (GreekGod)(comboBox.Items[0]);
    ComboBoxItem cbi1 = (ComboBoxItem)(comboBox.ItemContainerGenerator.ContainerFromIndex(0));
    ComboBoxItem cbi2 = (ComboBoxItem)(comboBox.ItemContainerGenerator.ContainerFromItem(comboBox.Items.CurrentItem));

This is because the generation of items for the ComboBox only happens when you open it. So the trick is to open the ComboBox before calling ContainerFromIndex/ContainerFromItem:

    GreekGod greekGod = (GreekGod)(comboBox.Items[0]);
    comboBox.IsDropDownOpen = true;
    ComboBoxItem cbi1 = (ComboBoxItem)(comboBox.ItemContainerGenerator.ContainerFromIndex(0));
    ComboBoxItem cbi2 = (ComboBoxItem)(comboBox.ItemContainerGenerator.ContainerFromItem(comboBox.Items.CurrentItem));
    comboBox.IsDropDownOpen = false;

Here you can find the VS project with this sample code. This works with September CTP WPF bits. Put a breakpoint at the end of the ButtonClick handler in Window1.xaml.cs to inspect the values of the variables.

6 Comments
  1. Pavan Podila

    I was trying out your example on the Feb CTP bits and it looks like the API is consistent for both ListBox and ComboBox. No special care (opening/closing the dropdown) needs to be taken for the ComboBox when using the Items property.

    • Bea

      Hi Pavan,

      I can’t repro that behavior - if I comment out the “comboBox.IsDropDownOpen = true;” line, I get null for the ComboBoxItems, as expected. Maybe you opened the ComboBox manually first to select an item (causing the generation of the items)?

      Let me know if this is the case.

      Bea

  2. Geoff

    I have a ItemsSource that is an ObservableCollection for my ComboBox, and I set SelectedItem to a field in another object. I would like the user to be able to select empty to specify they want the field set to null, but the ComboBox always seems to only display the items in the ObservableCollection.

    Any thoughts on how to add the empty item?

    I think I could have a separate ObservableCollection dependency property on my control and populate that from the real ObservableCollection + the empty item, but that seems like working around data binding rather than with it.

    • Bea

      Hi Geoff,

      I wonder if using a CompositeCollection would solve your problem. A CompositeCollection allows you to add a collection and individual items to an ItemsSource, all at the same time. You can read more about it in the MSDN documentation.

      Bea

      • Geoff

        Thanks! That works very nicely.

  3. kontrol

    This explains alot of my problems, thank you.

    IsSelected=”{Binding Path=IsCorrect}” doesn’t work for ComboBox but works for ListBox, now I know why. And now for a work around.

Comments are closed.