Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Step by Step WPF Data Binding with Comboboxes

0.00/5 (No votes)
30 Dec 2011 4  
A step by step set of examples that walk you through working with data binding and ComboBoxes.

Introduction

This article will teach you how to use data binding with ComboBoxes. It walks you through the following examples:

  1. Displays a string value and binds to a string value, all bindings in XAML. The ComboBox items collection is defined as a StaticResource in the application resources in the App.xaml.
  2. Displays a string value and binds to an enum value, all bindings in XAML.  The ComboBox items collection is defined as a list in the code behind file. In addition, this technique provides an easy way to get friendly translatable names for enums.

    These two examples will cover the basics on how to get data binding to work with ComboBoxes.

Intro.png

Background

There are many articles on the web that cover the topic of data binding. So why write another one? Good question. ComboBoxes have complications that don’t exist when you are binding to a control like a TextBox. With all of the articles out there, when I was trying to use a ComboBox for the first time, I didn't find a single article that clearly explained how to bind a ComboBox. In addition, I found many questions that didn't have complete answers. After finally figuring out how to get things to work, I decided to share my findings. The main difference with data binding and ComboBoxes are that there are actually 4 bindings that have to be set. This article walks you through, step by step, how to get each of the 4 data bindings to work with ComboBoxes.

Before jumping into working with ComboBoxes, I recommend you first read and understand the basics of data binding. Josh Smith has published several excellent articles on this subject here on CodeProject. This one,  A Guided Tour of WPF – Part 3 (Data binding), does an excellent job of explaining the basics of data binding. This one, Moving Toward WPF Data Binding One Step at a Time, walks you through getting data binding working with a TextBox. It is important to understand the basics covered in these articles before you try and tackle data binding with ComboBoxes.

The Examples in the Demo Application

This article covers the important points of data binding with ComboBox's in two separate examples. The second example builds off the first, so make sure you check out both examples to get a full understanding of this topic.

Databinding ComboBox Example #1

This example:

  • Displays a string value and binds to a string value.
  • All bindings are done in XAML.
  • The ComboBox items collection is defined as an application resource in the App.xaml file.
  • Note: The TextBlock beneath the ComboBox is bound to the same property as the ComboBox to prove the data binding is working. When you select a new value in the ComboBox the data object will be updated, it will send a property changed notification, the TextBlock will receive the property changed notification and it will be updated also.

Example1.png

Before looking at the bindings of the ComboBox, let's look at what we are going to be filling it with. First we create an array of three objects, of type ComboBoxItemString (which is a class defined in this project).The objects ValueString properties are set to: Red, Green, and Blue respectively.This collection is defined as a StaticResource in the application resources in the App.xaml file like this:

<Application.Resources>
    <x:Array x:Key="ColorListString" Type="local:ComboBoxItemString"/>
        <local:ComboBoxItemString ValueString = "Red" />
        <local:ComboBoxItemString ValueString = "Green"/>
        <local:ComboBoxItemString ValueString = "Blue"/>
    </x:Array>
</Application.Resources>

Now let's look at the ComboItemString class we are using above. It is defined in this project like this:

namespace ComboBoxDataBindingExamples
{
    /// This class provides us with an object to fill a ComboBox with
    /// that can be bound to string fields in the binding object.
    public class ComboBoxItemString
    {
        public string ValueString { get; set; }
    }
}

You can't get a much simpler class than this. All it has is one public property called ValueString of type string. So why is it needed?

This is where things get interesting, read this carefully. In order for data binding to work correctly, you need a 'property' to bind to. If we had an array of strings what property would we bind to? There aren't any. The only property on the string class is 'Length' and we don't want to bind to that. This is one of the issues that confused me when I first started trying to bind ComboBoxes. To make matters more confusing, you can use an array of strings to populate the ComboBox list if you don't use data binding. The reason that works is the ToString method is called to get the display value of the object. That's okay until you try to bind to it, that's when it doesn't work.

Let me repeat this because it is important, in order for data binding to work, you MUST bind to a PROPERTY on an object. The ComboBoxItemString class provides us with a property 'ValueString' to bind to.

Now let's look at the ComboBox definition in the XAML file. Here it is:

<ComboBox ItemsSource="{StaticResource ColorListString}" 
            DisplayMemberPath="ValueString" 
            SelectedValuePath="ValueString" 
            SelectedValue="{Binding ColorString}" />

The ComboBox has four properties that are set. Let's look at them one at a time.

  • ItemsSource - is bound to the static resource array 'ColorListString' that we defined above as an application resource in the App.xaml file. This list of items is used to populate the Items collection of the ComboBox. This collection is used to generate the items that show up in the dropdown list.
  • DisplayMemberPath - is bound to the ValueString property of the ComboBoxItemString object, in the ItemsSource list. When an item is selected from the dropdown list, this is the value that is displayed to the user.
  • SelectedValuePath - is bound to ValueString property of the ComboBoxItemString object, in the ItemsSource list. When an item is selected from the dropdown list, this is the property used to get the value to set the SelectedItem value to.
  • SelectedValue - is bound using a property binding of "{Binding ColorString}". When an item is selected in the list, this is the property on the data object that is set to the value returned from the SelectedValuePath property.

Looking at the binding above, you might think that the DisplayMemberPath and the SelectedValuePath are redundant since they bind to the same property, but they aren't. In the next example, you will see that we make use of the fact that these properties can be bound to two different values. Stay tuned.

But there are still two missing pieces. Do you know what they are? One of them is we haven't defined the data object we will be binding to and the other is that we haven't set the DataContext yet. All data binding are based on binding to a property on an object. The DataContext must be set to the object that contains the property you want to bind.

So what object are we bound to? Let's take a look. The rest is done in the code behind file. Here it is:

using System.Windows;

namespace ComboBoxDataBindingExamples
{
    public partial class Example1Window : Window
    {
        // Object to bind the combobox selections to.
        private ViewModelString viewModelString = new ViewModelString();

        public Example1Window()
        {
            // Set the data context for this window.
            DataContext = viewModelString;

            // Display the window
            InitializeComponent();
        }
    }
}

Could it be that this is the entire code behind file? It is except for some comments. This file only does a couple of things. Let's look at them one at a time.

  1. It has a private member viewModelString object which it assigns to a new instance of the ViewModelString class.
  2. The DataContext is set to be the viewModelString member that is part of this class. This means that the ComboBox's SelectedValue property binding is going to bind to a property called 'ColorString' on the ViewModelString class.

Ok, but what does the ViewModelString object look like. This is the final piece, hang in there. We know it has to have a public property called 'ColorString' or our binding won't work. Here is the entire ViewModelString class.

using System.ComponentModel;

namespace ComboBoxDataBindingExamples
{
    /// Class used to bind the combobox selections to. Must implement 
    /// INotifyPropertyChanged in order to get the data binding to 
    /// work correctly.
    public class ViewModel : INotifyPropertyChanged
    {
        /// Need a void constructor in order to use as an object element 
        /// in the XAML.
        public ViewModel()
        {
        }

        private string _colorString = "";

        /// String property used in binding examples.
        public string ColorString
        {
            get { return _colorString; }
            set
            {
                if (_colorString != value)
                {
                    _colorString = value;
                    NotifyPropertyChanged("ColorString");
                }
            }
        }

        #region INotifyPropertyChanged Members

        /// Need to implement this interface in order to get data binding
        /// to work properly.
        private void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }
}

This class contains the following items:

  • A void constructor so the class can be used as an object element in the XAML.
  • A string property, named 'ColorString', that is used to do the data binding to the ComboBox.
  • A NotifyPropertyChanged property which is required in order to get your bindings to work.

That's it. That wasn't that bad, was it.

Now we will build on this example by adding a few additional twists.

Databinding ComboBox Example #2

This example:

  • Displays a string value and binds to an enum value.
  • All binding are done in XAML. 
  • The ComboBox items collection is defined as a list in the code behind file.
  • This technique also provides an easy way to get friendly translatable names for enums.
  • Note: The TextBlock beneath the ComboBox is bound to the same property as the ComboBox to prove the data binding is working. When you select a new value in the ComboBox the data object will be updated, it will send a property changed notification, the TextBlock will receive the property changed notification and it will be updated as well.

Example2.png

Just like in the first example, we need to create an array of objects to display in ComboBox. This time, we will create the list in the code behind file since it introduces a different twist when dealing with the bindings. We'll look at this in more detail a little later.This is what the code looks like:

// Set up the collection properties used to bind the ItemsSource 
// properties to display the list of items in the dropdown lists.
// The string values are loaded from the resource file which can
// be translated into other languages.
ColorListEnum  = new List<ComboBoxItemColor>()
    {
        new ComboBoxItemColor(){ ValueColorEnum = ViewModelEnum.Colors.Red, 
			ValueColorString = Properties.Resources.RedText },
        new ComboBoxItemColor(){ ValueColorEnum = ViewModelEnum.Colors.Green, 
			ValueColorString = Properties.Resources.GreenText },
        new ComboBoxItemColor(){ ValueColorEnum = ViewModelEnum.Colors.Blue, 
			ValueColorString = Properties.Resources.BlueText },
    };

As you can see ,we are using a different object in this list than what we used in the first example. Let's take a look at the ComboBoxItemColor class we are using above. It is defined in this project like this:

namespace ComboBoxDataBindingExamples
{
    /// This class provides us with an object to fill a ComboBox with
    /// that can be bound to 'ViewModelEnum.Colors' enum fields in the binding
    /// object while displaying a string values in the to user in the ComboBox.
    public class ComboBoxItemColor
    {
        public ViewModelEnum.Colors ValueColorEnum { get; set; }
        public string ValueColorString { get; set; }
    }
}

Just like in the previous example, this is a very simple class. This class has two public properties called ValueColorString (type string) and ValueColorEnum (type ViewModelEnum.Colors). Since we want to display a string value and bind to an enum value, we need these two properties.

Now let's look at the ComboBox definition in the XAML file. Here it is:

<ComboBox ItemsSource="{Binding ColorListEnum}" 
            DisplayMemberPath="ValueColorString" 
            SelectedValuePath="ValueColorEnum" 
            SelectedValue="{Binding ViewModelEnum.ColorEnum}" />

Do you notice anything different about these bindings compared to the first example? There are some important differences. Let's look at them one at a time.

  • ItemsSource - is bound using a property binding of "{Binding ColorListEnum}". In the previous example, we had bound this to a static resource.
  • DisplayMemberPath - is bound to the ValueColorString property of the ComboBoxItemEnum object, in the ItemsSource list. Similar to the last example.
  • SelectedValuePath - is bound to the ValueColorEnum property of the ComboBoxItemString object, in the ItemsSource list. This is different than it was in the last example. We are binding to a different property than the DisplayMemberPath. This binding sets the SelectedItem to be the enum value while the display value is the string value. This explains why there are two properties.
  • SelectedValue - is bound using a property binding of "{Binding ViewModelEnum.ColorEnum}". At first glance, this might look similar to the first example, but there is an important difference. Do you see it? In this example, we are binding to a property (ColorEnum) of a property (ViewModelEnum), but why? The answer has to do with the change to our ItemsSource binding and a change to our DataContext, keep reading.

Just like in the first example, the rest is done in the code behind file. Here it is:

using System.Windows;
using System.Collections.Generic;

namespace ComboBoxDataBindingExamples
{
    public partial class Example2Window : Window
    {
        // Collection property used to fill the ComboBox with a list
        // of ComboBoxItemColor objects that contain colors options.
        public List<ComboBoxItemColor> ColorListEnum { get; set; }

        // Object to bind the combobox selections to.
        public ViewModelEnum ViewModelEnum { get; set; }
        private ViewModelEnum viewModelEnum = new ViewModelEnum();

        public Example2Window()
        {
            // Set the property to be used for the data binding to and from
            // the ComboBox's.
            ViewModelEnum = viewModelEnum;

            // Set up the collection properties used to bind the ItemsSource 
            // properties to display the list of items in the dropdown lists.
            // The string values are loaded from the resource file which can
            // be translated into other languages.
            ColorListEnum  = new List<ComboBoxItemColor>()
                {
                    new ComboBoxItemColor(){ ValueColorEnum = ViewModelEnum.Colors.Red, 
				ValueColorString = Properties.Resources.RedText },
                    new ComboBoxItemColor(){ ValueColorEnum = ViewModelEnum.Colors.Green, 
				ValueColorString = Properties.Resources.GreenText },
                    new ComboBoxItemColor(){ ValueColorEnum = ViewModelEnum.Colors.Blue, 
				ValueColorString = Properties.Resources.BlueText },
                };

            // Set the data context for this window.
            DataContext = this;

            // Init the window
            InitializeComponent();
        }
    }
}

This class is a lot different than in the first example. Let's look at things one at a time.

  • ColorListEnum - This property is the property the ItemsSource binds to. This replaces the StaticResource. It is sometimes useful to be able to bind to a collection that is defined in code behind. This is how you do it. Notice that this is a property and not a data member, this enables the binding.
  • ViewModelEnum - The SelectedValue property binds to the ColorEnum property through this property. Notice the SelectedValue binding is set to "{Binding ViewModelEnum.ColorEnum}". In this case, we are binding to a property of a property.
  • viewModelEnum - This is the data member the above property is set to. Remember you cannot bind directly to a data member.
  • ColorListEnum - is initialized to a List containing three ComboBoxItemColor objects. This is equivalent to the static resource in the first example.
  • DataContext - is set to this window.

Wait a minute. In the first example, the DataContext was set to the view model class. Couldn't we have done that here. No we couldn't. Can you figure out why? It's because we are NOT binding the ItemsSource to a static resource. Confused yet? It was the first time I tried this.

This is one of the most confusing parts of data binding and ComboBox's. Let's walk through it slowly. You only have one DataContext for a ComboBox, or any other control for that matter. This means (if your ItemsSource is being bound to a code behind property) that the DataContext of your ComboBox must contain two properties for your ComboBox to bind to. The first property is for your ItemsSource collection (in this case ColorListEnum) and a second property for your SelectedValue property (in this the ColorEnum property on the ViewModelEnum property). This is an important difference when binding a ComboBox versus a simple control like a TextBox.

Now we will take a look at the ViewModelEnum class. Here it is in its entirety.

using System.ComponentModel;

namespace ComboBoxDataBindingExamples
{
    public class ViewModelEnum : INotifyPropertyChanged
    {
        /// Enum used by the combobox and the view model.
        public enum Colors
        {
            Red = 1,
            Green = 2,
            Blue = 3,
        }

        /// Need a void constructor in order to use as an object element 
        /// in the XAML.
        public ViewModelEnum()
        {
        }

        private ViewModelEnum.Colors _colorEnum = ViewModelEnum.Colors.Red;

        /// ViewModelEnum.Colors Enum property used in binding examples.
        public ViewModelEnum.Colors ColorEnum
        {
            get { return _colorEnum; }
            set
            {
                if (_colorEnum != value)
                {
                    _colorEnum = value;
                    NotifyPropertyChanged("ColorEnum");
                }
            }
        }

        #region INotifyPropertyChanged Members

        /// Need to implement this interface in order to get data binding
        /// to work properly.
        private void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }
}

The big difference here from the first example is that this class contains the enum we want to store in the view model. This same technique could be used if the enum were defined in a separate class.

That's it. You now know everything you need to know when it comes to data binding and ComboBoxes.

Using the Code

I have included the Visual Studio 2010 project that contains all of the source code you need to run these examples. I have also included the application if you just want to run it.

History

  • First version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here