Binding to a Combobox

Before we can get to the “gotcha” I came across, we first need to set up how to use binding with a Combobox.  For my example we will be using a simplistic MVVM architecture because it helps to demonstrate the point a bit better.  Just as a reminder, you don’t have to use binding with the Combobox or to recreate the issue described in this post.

So let’s get started with our view model.  For our purposes, the view can be rather simplistic, needing only 2 properties.  I added a method to populate our list data just for completion.

    public class MainPageViewModel : INotifyPropertyChanged
    {
        private string _favoriteConf;

        public MainPageViewModel()
        {
            PopulateConfs();
        }

        public string FavoriteConf
        {
            get { return _favoriteConf; }
            set
            {
                _favoriteConf = value;
                NotifyPropertyChanged("FavoriteConf");
            }
        }

        private List<string> _confs;

        public List<string> Confs
        {
            get { return _confs;  }
            set
            {
                _confs = value;
                NotifyPropertyChanged("Confs");
            }
        }
        private void PopulateConfs()
        {
            Confs = new List<string>()
                {"MIX", "TechEd", "PDC", "DevConnections"};
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        protected  void NotifyPropertyChanged(string propertyName)
        {
            if(PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion
    }

As you can see, we have just the two properties : FavoriteConf and Confs.  Our constructor calls the PopulateConfs to add some data for us to work with.  (Yes, Conf = Conference, I just didn’t want to write out Conference too many times. ).

Now that we have our view model, the next step would be to create our XAML.  For this demonstration, we are going to show two elements: a Combobox and a TextBox.  The Combobox will have our list of conferences (bound to the Confs property) and the TextBox will show the selected conference by binding to the the FavoriteConf property.

If you look at the Combobox, you will notice two different binding statements.  The first one is the ItemsSource is bound to the Confs property.  This is done with the default OneWay binding, since our Combobox will never be modifying the list of data.  The second is the SelectedValue with is bound to the FavoriteConf property.  Since we want to update the FavoriteConf value in our view mode when the user selects a drop down, then we do a two-way binding.

Here is our XAML:

<UserControl x:Class="ComboBoxBinding.MainPage"
    xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
    xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
    xmlns:d=http://schemas.microsoft.com/expression/blend/2008
    xmlns:mc=http://schemas.openxmlformats.org/markup-compatibility/2006
    xmlns:local="clr-namespace:ComboBoxBinding"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    <UserControl.Resources>
        <local:MainPageViewModel x:Key="viewModel"/>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="White"
          DataContext="{StaticResource viewModel}">
        <Grid HorizontalAlignment="Center" VerticalAlignment="Center"
              Background="LightGray"
              Height="Auto" Width="Auto">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="150"/>
                <ColumnDefinition Width="150"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="25"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <TextBlock HorizontalAlignment="Center"
                       Text="Select Favorite Conference"/>
            <TextBlock Text="Choose One :" Grid.Row="1"/>
            <ComboBox Grid.Row="1" Grid.Column="1"
                      SelectedValue="{Binding FavoriteConf, Mode=TwoWay}"
                      ItemsSource="{Binding Confs}"/>
            <TextBlock Text="You Picked :" Grid.Row="2"/>
            <TextBox Text="{Binding FavoriteConf}" Grid.Row="2"
                     Grid.Column="1"/>
        </Grid>
    </Grid>
</UserControl>

Note: Since this is a demonstration, I’m creating a static copy of our view model in the resources of our XAML and binding the LayoutRoot’s DataContext to this resource.

If you run the project the application should look something like this:



When you select an item from the Combobox, the TextBox will update with the selected value of the Combobox.



Great! It works, everything is add it should be, right?

Note: Silverlight 4 added some additional properties to the Combobox to make binding easier.  You can read a walkthru of using them on John Papa’s blog
here.

Ordering of XAML Properties : The Gotcha

So let’s take our example one step further, but setting a default value for our FavoriteConf value.  To do this, we are going to change up our constructor to our view model by adding another line of code:

        public MainPageViewModel()
        {
            PopulateConfs();
            FavoriteConf = "MIX";
        }

If we run our example again, this is what we get:



Not exactly what I was looking for.  The TextBox picked up the default value of the FavoriteConf, but why didn’t the Combobox?  Well it turns out, after much head scratching, that the answer is in our XAML.

Let’s take a look at the XAML of our Combobox again:

            <ComboBox Grid.Row="1" Grid.Column="1"
                      SelectedValue="{Binding FavoriteConf, Mode=TwoWay}"
                      ItemsSource="{Binding Confs}"/>

Do you see where we went wrong?

It looked right to me for a while.  However, it turns out that ordering of the properties in XAML can affect the behavior of the control.  If we switch the order of the ItemsSource and the SelectedValue, your XAML will now look something like this:

            <ComboBox Grid.Row="1" Grid.Column="1"
                      ItemsSource="{Binding Confs}"
                      SelectedValue="{Binding FavoriteConf, Mode=TwoWay}"/>

Now, if we run the two examples side-by-side, we get the following:



It turns out that ordering in your XAML can be important and something to look out for if you are not getting the results that you are looking for. If you have found yourself in a similar situation, hopefully this will post will help.