Binding to a ComboBox to a Dictionary in Silverlight using MVVM

Often you just need to bind a list of items or observable collection to a combobox, but sometimes its advantageous to bind a dictionary to a combobox. Binding a dictionary in silverlight is a little tricky, so here is how to do it.



 

img2.jpg


Introduction

Most binding in WPF is pretty straightforward (such as binding a TextBlock to a string), but binding to a more complex data structure is not as intuitive.  This article explains how to bind a Dictionary in your ViewModel to a ComboBox.

The View Model

Let's say we wanted to show a list of states in our combobox, but when the user selected a state, we only wanted to retrieve the state code from the combobox. How might we go about doing this?   For example, if the user chooses Texas, I want the combobox to return TX the abbreviation for Texas.
The easiest way to do this is to maintain a list of  (Key, Value) pairs in the viewmodel.  We'll start by creating a static dictionary to maintain all our states.  In practice, it would probably be better to read these out of a file, but for the sake of the example, we'll hard-code all the states in our ViewModel.

Listing 1 - States maintained in a static Dictionary

private static readonly Dictionary<string, string> StateData = new Dictionary<string, string>   {

                                                                     {"AR", "Arkansas"},                                                                              {"AL", "Alabama"},                                                                               {"AK", "Alaska"},                                                                                   {"AZ", "Arizona"},                                                                               {"CA", "California"},                                                                                  {"CO", "Colorado"},                                                                              {"CT", "Connecticut"},                                                                                  {"DE", "Delaware"},
                                                                          ...

 
Also in our ViewModel, we'll add a property States to the view of type Dictionary in which we can bind to the combobox and we'll assign it the stateData in the constructor.

Listing 2 - Property we will bind to our ViewModel

public AddressViewModel()
             
{
                    
States = StateData;
             
}

             
private Dictionary<string, string> states;
             
public  Dictionary<string, string> States
             
{
                    
get { return states; }
                    
set {

                          
 states = value;
                           
PropertyChanged(this, new PropertyChangedEventArgs("States"));
                        
}
             
}



In the combobox, we'll use the Value part of the Dictionary to display the choices to the user.  But we'll also want a property called SelectedState to bind to the selected value, so we can capture the state abbreviation  selected by the user.

Listing 3 - Property for binding to the selected item chosen by the user in the combobox

public string SelectedState
             
{
                    
get { return _selectedState; }
                    
set
                    
{
                          
_selectedState = value;
                          
PropertyChanged(this, new PropertyChangedEventArgs("State"));
                    
}
             
}


Now we're ready to bind to the view model to the actual ComboBox in our XAML mark up.


The XAML

The first thing we need to do in our UserControl is to instantiate the view model.  We can do this directly in the Resources of the page.

Listing 4 - Instantiating the view model in XAML

<UserControl.Resources>
       
<ViewModel:AddressViewModel  x:Key="addressViewModelKey" />
   
</UserControl.Resources>

We can use the key of the instantiated view model instance, addressViewModelKey, to assign to the data context of our UserControl.  We can do this easily by setting the data context in the LayoutRoot grid.

Listing 5 - Hooking up the view model to the data context

    <Grid x:Name="LayoutRoot" Background="White" DataContext="{StaticResource addressViewModelKey}">

Now that our ViewModel is bound to our page we are ready to bind our dictionary to the ComboBox.

Binding to the Combo

The ItemsSource property allows us to bind our combobox directly to the Dictionary States in our ViewModel.  However, in order to display the correct choices in our combo and pick the correct value, we'll need a few helper properties.  The combobox has several properties that make  it easier to bind to the dictionary for display and selection purposes.  The properties are DisplayMemberPath, SelectedValuePath, and SelectedValue.  The DisplayMemberPath let us choose which property of the KeyValuePair in the Dictionary we will display.  In a KeyValuePair there are only two choices: Key and Value.  In our example, we want to display the full state name, so we'll choose to bind the DisplayMemberPath to the Value.  The SelectedValuePath let's us choose what property of our KeyValuePair we will actually return when the user makes a selection.  We only want the abbreviation or the Key of the Dictionary, so we'll bind SelectedValuePath to the Key.   Now whatever we bind to SelectedValue in our ViewModel will return the Key of the selected KeyValuePair.  In this case we bind the SelectedState property of the ViewModel to the SelectedValue to capture the abbreviated state in this property.

Listing 6 shows the binding of the ComboBox to our ViewModel. As you can see, the ItemsSource of the ComboBox is bound to our States Dictionary.  DisplayMemberPath is bound to Value of our dictionary item,  SelectedValue is bound to the SelectedState property and SelectedValuePath chooses the Key of our dictionary item.

Listing 6 - Binding our ViewModel to the ComboBox

        <ComboBox Height="25" HorizontalAlignment="Left" Margin="100,68,0,0" Name="StatesComboBox" VerticalAlignment="Top" Width="204" ItemsSource="{Binding States}" DisplayMemberPath="Value" SelectedValuePath="Key" SelectedValue="{Binding SelectedState, Mode=TwoWay}" />

Conclusion

Moving to MVVM gives us a clean way to separate our data layer from our presentation layer, but at the same time gives us a binding mechanism to marry the two layers.   If we want to populate a combobox through the ViewModel, we have the option of using a dictionary.  A dictionary gives us the ability to store additional information along with each choice displayed to the user in the combobox.  Microsoft has provided some properties to help us along picking what we want to display as choices and what we want to the ViewModel to select from the choice.  In any case, the .NET development platform gives us a combonation of things we can do to make the user experience and the programming experience in Silverlight a breeze.