Follow Me on Instagram Subscribe via RSS Feed

Binding to a ComboBox in Silverlight : A Gotcha

February 13, 2011

I am often asked what my favorite feature of Silverlight is, and my answer in always “binding”.  The binding in Silverlight and WPF was finally done right and it is an incredibly powerful tool.  However, you still run into a few “gotcha’s” every once and a while and one happened to me the other day with the Combobox.  If binding to a Combobox is nothing new to you, then you can skip past the Binding to a Combobox section to the description and setup of the issue.


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:

image

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

image

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:

image

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:

image

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.

You can download the code for this example here: download source

27JBPHZ47UJC

Comments (6)

Trackback URL | Comments RSS Feed

  1. Kevin Dockx says:

    We actually experienced this on a project once, literally cost us days until we found out what the problem was – great tip!

  2. George says:

    Wow! That’s so much. I’ve been scratching my head tryign to figure this one out.

  3. Colin E. says:

    This is unfortunately an issue in WPF also …

    http://www.hardcodet.net/2009/01/xaml-binding-declaration-order-matters

    At least it is consistent!

  4. Marco P. says:

    Very usefull! I lost more than one hour trying to find what was wrong on my vm before finding your post…darn!

  5. Anil kumar says:

    Tony

    Artilcle is Awesome. Nice thing to know. I have one clarification, Actually When I bind the

    ComboBox with List of “Entity” instead of List of “String” then its not setting the Default

    “SelectedValue” Property. If you have any idea or i might have did any mistake. Then

    please get back to me.

    Thanks

Leave a Reply