WPF ComboBox and DataBinding: DataContext, ItemsSource, DisplayMemberPath, SelectedItem, SelectedValue & SelectedValuePath

Coding / WPF

A few weeks ago, a friend convinved me to start looking into WPF, XAML and the MVVM pattern.  As I’ve been primarily working with ASP.NET WebForms & MVC2 applications and core system design/development, I haven’t had any exposure to these new(er) technologies, and I thought it might be fun to see what all of the fuss is about.

Note that the information in this post may also be applied to other controls implementing ItemsControl.Selector, e.g. a ListBox.  I am using terms in this post in a way which assumes that you are using the MVVM pattern.

Along the way, I came across a situation where I needed to do some different kinds of binding using ComboBoxes. My specific case was a bit more complex because I was binding to the page ViewModel (which I didn’t want to instantiate more than once as it made web service calls) to a ComboBox in a DataTemplate for a cell in a GridView. There wasn’t much documentation regarding that which I found that was helpful, so I’ll do another post about that later. In this post I’ll just cover what I learned about basic data binding, so here is what I needed to do, without all of the DataTemplate/GridView bloat :)

  • I needed the source of the items in the ComboBox to come from one ViewModel, and I needed to bind the original object of the currently selected item to a property in another ViewModel.
  • I needed the source of the items in the ComboBox to come from one ViewModel, and I needed to bind a property of the original object of the currently selected item to a property in another ViewModel.

Note that in my case, the ViewModel which the ComboBox needed to get its items from was the DataContext of the page and the DataContext of the ComboBox was the ViewModel which I needed to bind values to.

Common DataBinding Properties

Now, all of that aside, let’s go over the more common properties used in DataBinding to a Selector control.  Note that when I refer to the ViewModel I’m assuming that the DataContext of the page is set to your ViewModel instance and that the ComboBox has inherited that DataContext.

  • DataContext (FrameworkElement) - The object which will be the default binding source for the ItemsSource, SelectedItem and SelectedValue properties.
  • DisplayMemberPath (ItemsControl) - As the Selector iterates through its list of items, if you don’t want to display the object’s .ToString() value you can specify a path to a property here.  For example, if the item is of type “Customer” (meaning your ItemsSource binds to an ObservableCollection<Customer> or similar property) which has a property @Name of type Name { FirstName, LastName } and you want to display the customer’s first name.  To do this, you would set DisplayMemberPath=”Name.FirstName”.
  • SelectedItem (Selector) – Binds the ACTUAL object in the ItemsControl which is selected (which would be your “Customer” object in the previous example).  If you want to bind the actual item, you can specify your binding property in your ViewModel here.  For example, SelectedItem=”{Binding Path=SelectedCustomer, Mode=TwoWay}” would bind the selected Customer object to the SelectedCustomer property in your ViewModel (and since I didn’t specify a binding source, that would default to the DataContext).
  • SelectedValue & SelectedValuePath (Selector) - Specifies the binding which the property from the selected item at the path provided in SelectedValuePath should be bound to.  Using our customer example, if you wanted to bind the selected customer’s @Name.FirstName property to a property named SelectedCustomerFirstName on your ViewModel, you would set your SelectedValue=”{Binding SelectedCustomerFirstName}” and SelectedValuePath=”Name.FirstName”.

Getting our Hands Dirty

Now that we’ve got a decent understanding of the common binding properties of a Selector control (I hope!), let’s move onto an example.  Given the following classes (only class signatures; the full sample project including source code is attached to this post):

Country.cs

public class Country
{
    public string Name { get; set; }
    public string TwoLetterCode { get; set; }
}

ShippingMethod.cs

public class ShippingMethod
{
    public byte ID { get; private set; }
    public string Name { get; private set; }
    public bool IsWorldWide { get; private set; }
    public IEnumerable<Country> DestinationCountries { get; }
}

ShippingCarrier.cs

public class ShippingCarrier
{
    public byte ID { get; private set; }
    public string Name { get; private set; }
    public IEnumerable<ShippingMethod> ShippingMethods { get; }
}

And we have a ViewModel which has the following property signature:
MainWindowViewModel.cs

public class MainWindowViewModel : ViewModel
{
        public ObservableCollection<ShippingCarrier> ShippingCarriers { get; private set; }
        public ObservableCollection<Country> Countries { get; private set; }
        public ObservableCollection<ShippingCarrier> AvailableShippingCarriers { get; private set; }
        public ObservableCollection<ShippingMethod> AvailableShippingMethods { get; private set; }

        public bool AllowShippingCarrierSelection { get; }
        public bool AllowShippingMethodSelection { get; }
        public string SelectedSourceCountryTwoLetterCode { get; set; }
        public Country SelectedDestinationCountry { get; set; }
        public ShippingCarrier SelectedShippingCarrier { get; set; }
        public ShippingMethod SelectedShippingMethod { get; set; }
}

Then we can start working with some binding! In the following XAML, the ComboBox is populated from the Countries property on the ViewModel (ItemsSource). Each item in the ComboBox is an object of type Country and the ComboBox will display the Name property from the Country object (DisplayMemberPath). When the user selects an item in the drop-down, the SelectedSourceCountryTwoLetterCode property on the current DataContext of the ComboBox (our ViewModel in this case) will be set to the TwoLetterCode property from the selected Country object (SelectedValuePath).

<ComboBox
    ItemsSource="{Binding Countries, Mode=OneWay}"
    DisplayMemberPath="Name"
    SelectedValue="{Binding SelectedSourceCountryTwoLetterCode}"
    SelectedValuePath="TwoLetterCode" />

And here’s an example where we use SelectedItem to bind the selected Country object to the SelectedDestinationCountry property on the DataContext (still our ViewModel):

<ComboBox
    ItemsSource="{Binding Countries, Mode=OneWay}"
    DisplayMemberPath="Name"
    SelectedItem="{Binding SelectedDestinationCountry}" />

Note the use of “Mode=OneWay” in my ItemsSource bindings. This indicates to the binding that we’re only going to be updating the binding target (the ComboBox’s Items collection in this case). For the SelectedItem and SelectedValue bindings, I do not set a mode – this is because “Mode=TwoWay” is the default. TwoWay means that we want to update the property on the ViewModel when the selection changes, and if the property on the ViewModel changes we want to update the SelectedItem/SelectedValue on the ComboBox. You can read more about the different binding modes here.

Well i hope this helps somebody!  Happy binding :-)

Cyle


Programming enthusiast. I've been intrigued by computers since I was 12, staying in at recess to code QBASIC on the old Apple II. Background in the payment industry, particularly in card switching and related system architecture. Lover of high-performance distributed architecture. Huge fan of the new NoSQL wave. Open source fanatic.

9 Comments

  1. Alastair
    12 June 11, 1:24am

    Nice, clean and concise explanation. I was beating my head off the wall trying to implement this – many thanks.

  2. Robert
    11 February 12, 12:04am

    Your explanation is very good: You give first a clear foundation and bring that step by step into practice. That’s the way to communicate the complexity of e.g. WPF. Thanks :-)

  3. 19 November 12, 7:27am
  4. 02 February 13, 9:10pm

    Dear Cyle,
    I really enjoyed your code :)
    its awesome. Thanks for this nice and easy tutorial. Much appreciated :)

  5. Raghu
    24 April 13, 3:08pm

    Thanks , It helped .

  6. Atul Kumar
    09 May 13, 2:58pm

    Thank you so very very very much. I had been beating my head for last more than 5 days but was not able to understand this. But your example made me understand. Very neat and clear example. Thank you so much. :)

    • 31 May 13, 9:04am

      Thanks :) Glad it helped! /Cyle

  7. Neha
    23 July 13, 1:15pm

    hi

    Does two way binding work for SelectedItem or Selected Value in combobox?

    Thanks in advance
    Regards
    Neha

Respond to CodeProblem