Blog

Books

Books I tech reviewed and recommend
Sorry I can't reply to every email and comment. If you need a fast response, try the WPF Forum or Silverlight Forum.
September 27, 2005

How do I bind the items of a ComboBox? How do I get a ComboBoxItem from a data bound ComboBox?

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.


Posted by Bea under WPF | Comments (6)

September 21, 2005

How can I get a ListBoxItem from a data bound ListBox?

Data binding a list box to an enumeration of items could not be easier in WPF:

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

The ItemsSource property of ListBox takes an IEnumerable, which is the list of items you want to display. In this case, the GreekGods data source is of type ObservableCollection, which implements IEnumerable. The ItemTemplate property specifies the DataTemplate that will be used to control how the data is displayed. In this case, we will have a TextBlock for each item that will display the GreekGod’s name.

Some of you might find surprising, however, that doing listBox.Items[i] in code returns the data we’re binding to, and not the TextBlock or the ListBoxItem. In my opinion, it is actually pretty cool that retrieving the data in a particular position of the list box is so easy, because most of the time this is exactly what you want.

    GreekGod greekGod = (GreekGod)(listBox.Items[0]);

But what about when you want to have access to the actual ListBoxItem generated? This is a bit tricky to discover but can be just as easily done with the following code:

    ListBoxItem lbi1 = (ListBoxItem)(listBox.ItemContainerGenerator.ContainerFromIndex(0));

There is also a listBox.ItemContainerGenerator.ContainerFromItem(object item) that returns the ListBoxItem given the corresponding data item. This method is frequently used, for example, to retrieve the ListBoxItem for the current item:

    ListBoxItem lbi2 = (ListBoxItem)(listBox.ItemContainerGenerator.ContainerFromItem(listBox.Items.CurrentItem));

I will talk about selection and current item in detail in some other post, but for this sample it is sufficient to know that to keep the selection and current item in sync, I set IsSynchronizedWithCurrentItem=”true” in the ListBox.

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.

Update: You can download the WPF 3.5 (VS 2008) version of this post, or the Silverlight 3 version.

Posted by Bea under WPF | Comments (17)

September 11, 2005

What does “{Binding}” mean?

Most Bindings you see in samples have the Source and Path properties set. The Source property specifies the object you’re binding to and the Path specifies a property in that object whose value you’re interested in. I’ve seen several people get confused when encountering an empty Binding for the first time – “{Binding}”. It seems at first sight that we’re not giving the Binding enough information to do anything useful. This is not true and I will explain why. If you read my previous post you should understand that it is not necessary to set a Source in a Binding, as long as there is a DataContext set somewhere up in the tree. As for the Path, it should be left out when you want to bind to a whole object, and not only to a single property of an object. One scenario is when the source is of type string and you simply want to bind to the string itself (and not to its Length property, for example).

    <Window.Resources>
        <system:String x:Key="helloString">Hello</system:String>
    </Window.Resources>
    
    <Border DataContext="{StaticResource helloString}">
        <TextBlock TextContent="{Binding}"/>
    </Border>

Another common scenario is when you want to bind some element to an object with several properties.

    <Window.Resources>
        <local:GreekGod Name="Zeus" Description="Supreme God of the Olympians" RomanName="Jupiter" x:Key="zeus"/>
    </Window.Resources>
    
    <Border DataContext="{StaticResource zeus}">
        <ContentControl Content="{Binding}"/>
    </Border>

In this case, ContentControl does not know how to display the GreekGod data. Therefore you will only see the results of a ToString(), which is typically not what you want. Instead, you can use a DataTemplate, which allows you to specify the appearance of your data.

    <Window.Resources>
        <local:GreekGod Name="Zeus" Description="Supreme God of the Olympians" RomanName="Jupiter" x:Key="zeus"/>
        <DataTemplate x:Key="contentTemplate">
            <DockPanel>
                <TextBlock Foreground="RoyalBlue" TextContent="{Binding Path=Name}"/>
                <TextBlock TextContent=":" Margin="0,0,5,0" />
                <TextBlock Foreground="Silver" TextContent="{Binding Path=Description}" />
            </DockPanel>
        </DataTemplate>
    </Window.Resources>
    
    <Border DataContext={StaticResource zeus}">
        <ContentControl Content="{Binding}" ContentTemplate="{StaticResource contentTemplate}"/>
    </Border>

Notice that none of the Binding statements inside the DataTemplate has a Source. That is because a DataContext is automatically set to the data object being templated.

Here you can find the VS project with this sample code. This works with Beta 1 WPF bits.


Posted by Bea under WPF | Comments (2)

September 7, 2005

How should I decide whether to use DataContext or Source?

DataContext is one of the most fundamental concepts in Data Binding.

The Binding object needs to get its data from somewhere, and there are a few ways to specify the source of the data. In this post I talk about setting the Source property directly in the Binding vs inheriting a DataContext from the nearest element when traversing up in the tree. The other two alternatives are setting the ElementName and RelativeSource properties in the Binding object, but I will leave that for a future post.

For example, let’s assume we have the following data sources (GreekGod being a class defined in the code behind):

    <Window.Resources>
        <local:GreekGod Name="Zeus" Description="Supreme God of the Olympians" RomanName="Jupiter" x:Key="zeus"/>
        <local:GreekGod Name="Poseidon" Description="God of the sea, earthquakes and horses" RomanName="Neptune" x:Key="poseidon"/>
    <Window.Resources>
    
    <StackPanel DataContext="{StaticResource poseidon}">
        <TextBlock TextContent="{Binding Source={StaticResource zeus}, Path=Name}"/>
        <TextBlock TextContent="{Binding Path=Description}"/>
        <TextBlock TextContent="{Binding Path=RomanName}"/>
    <StackPanel>

The first TextBlock inherits the DataContext from the parent StackPanel and has a Source set in the Binding object too. In this case, Source takes priority, causing the TextBlock to bind to the Name property of the resource with key “zeus” – this displays “Zeus”.

The second TextBlock does not have a Source set directly in the Binding object, so it inherits the DataContext from the StackPanel. As you might guess, this binds to the Description property of the resource with key “poseidon”, displaying “God of the sea, earthquakes and horses”.

The third TextBlock should be straightforward – it displays “Neptune”.

Most data bound applications I see from users tend to use DataContext much more heavily than Source. My recommendation is to use DataContext only when you need to bind more than one property to a particular source. When binding only one property to a source, I always use Source. The reason for this is ease of debugging – I would rather see all the information about the Binding in one place than search for the nearest DataContext to understand what is going on. In a small sample like the one above there is no big advantage, but in complex applications this could save you some time.

Here you can find the VS project with this sample code. This works with Beta 1 WPF bits.

Posted by Bea under WPF | Comments (0)