Introduction

In this article, I will show you how to create an EnumerationComboBox, this will be a nice and easy way for us to bind enumerations to ComboBoxes.

The Problem

Databinding is great - MVVM in WPF allows us to create ViewModels that contain data and logic, and Views, which handle the presentation of that data. However,
if you're anything like me, you double take when you have to bind a combo box to an enumeration. How does that work again?

Normally when you use a combo box, you specify an ItemsSource - this is the set of items that can be selected, and a SelectedItem - the actual item that has
been selected. Typically, in a ViewModel, you may have a property which is an enumeration, but you cannot just bind to this - you also need the ItemsSource - the collection
of available enumeration values.

To provide this data, we can use an ObjectDataProvider - this is a fairly straightforward mechanism, but a little tedious. In this article, we'll create
a combo box with a new property - SelectedEnumeration, which will handle all the tedious stuff for us.

The Enumeration

I love Futurama. So let's create an enumeration that represents some of the main characters.

publicenum Character
{
Fry,
Leela,
Zoidberg,
Professor
}

Here is a fairly simple enumeration. Now we'll create a View Model which exposes a property of type 'Character'.

Introducing the ViewModel

Now let's create a ViewModel.

///<summary>/// The MainViewModel. This is the main view model for the application.
///</summary>publicclass MainViewModel : ViewModel
{
///<summary>/// The Character notifying property.
///</summary>private NotifyingProperty CharacterProperty =
new NotifyingProperty("Character", typeof(Character), Character.Fry);
///<summary>/// Gets or sets the character.
///</summary>///<value>/// The character.
///</value>public Character Character
{
get { return (Character)GetValue(CharacterProperty); }
set { SetValue(CharacterProperty, value); }
}
}

If you are unfamiliar with the base class ViewModel, then don't worry. It is the base class for all View Models when you are using the Apex library.
The NotifyingProperty object just handles the ins-and-outs of INotifyPropertyChanged for us. If you are using your own implementation of
INotifyPropertyChanged, a framework such as Prism or Cinch, then just create the equivalent ViewModel. The important thing is that it exposes a property of type
Character.

The View

Finally, we define the View. This is the most simple definition - the one in the example application has a grid and some text to improve the layout.

<Windowx:Class="EnumerationComboBoxSample.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="clr-namespace:EnumerationComboBoxSample"Title="EnumerationComboBox Sample"Height="191"Width="442"><!-- Set the data context to an instance of the view model. --><Window.DataContext><local:MainViewModelx:Name="mainViewModel"/></Window.DataContext><StackPanelOrientation="Vertical"><!-- The label for the combo box. --><LabelContent="Selected Character"/><!-- The combo box, bound to an enumeration. --><ComboBoxSelectedItem="{Binding Character}"/></StackPanel></Window>

This is what we'd like to do - just bind to SelectedItem. However, if we run the application up,
we'll see that the combo box doesn't work - there's no set of items to select from.

How do we resolve this problem?

The Common Solution

The most typical way to bind an enum to a combo box is to use an ObjectDataProvider to provide the data for the ItemsSource, as below:

But this is clunky - we have to create an ObjectDataProvider for each type of enum, remember the syntax, yada yada yada.

A Better Solution

What if we could just bind like this:

<!-- The combo box, bound to an enumeration. --><ComboBoxSelectedEnumeration="{Binding Character}"/>

and have all the hard work done for us? Well, we're using C# and WPF, so generally, if you can imagine it, you can do it. So let's create a combobox that works like this.

First, we'll create a new class derived from ComboBox which will be specifically for the task we've set ourselves.

///<summary>/// A EnumerationComboBox shows a selected enumeration value
/// from a set of all available enumeration values.
/// If the enumeration value has the 'Description' attribute, this is used.
///</summary>publicclass EnumerationComboBox : ComboBox
{

So far so good. Now the next thing we know is that we'll need a new dependency property - one that represents the SelectedEnumeration. The plan is that when this
property is set, we'll create our own ItemsSource on the fly. Create the dependency property as below.

This property will almost certainly be set via a binding in XAML, i.e., the user of the control sets the initial property. However, we want to change the
selected enumeration when a new value is selected from the combo box, so we will always want it to be bound two ways. This is fine - except in Silverlight, which
doesn't have the BindsTwoWaysByDefault option! In Silverlight, the best we can do is hope the user remembers to bind two ways!

Just like most controls in Apex, EnumerationCombobBox works for WPF, Silverlight, and WP7, so we are very careful to understand
the differences between WPF and Silverlight such as this!

We've specified that the function OnSelectedEnumerationChanged will be called when the property is changed - this is where we can hook up our logic to create
the ItemsSource.

Now we can build a function 'PopulateItemsSource' that will set the ItemsSource property.

As we're going to the effort of doing all this - let's allow the user to specify descriptions for the enumerations using the System.ComponentModel.Description attribute.
Our enumeration will look like this:

///<summary>/// Populates the items source.
///</summary>privatevoid PopulateItemsSource()
{
// We must have an items source and an item which is an enum.
if (ItemsSource != null || SelectedEnumeration is Enum == false)
return;

Now there's no need to re-create the ItemsSource if it's already been set, so the first thing we do is bail out of the function if we've already done the work.

All we have done here is build the list of enumerations. We use the Apex.Helpers.EnumHelper class as Enum.GetValues doesn't exist in Silverlight.
EnumHelper works for Silverlight, WPF, and Windows Phone 7. Then we set the ItemsSource and call
Initialise (for any final initialization that must be done). Initialise is just the code below:

Initialise simply sets the initial value (if there is one!) and creates an event handler for the SelectionChanged event. The event handler just sets the
SelectedEnumeration value (so that when the user changes the selected item, the bound SelectedEnumeration is set as well).

The only function that is left to do now is one that gets the Description of an enum, or just returns it as a string if it isn't set; we can do this by building an Extension Method.

///<summary>/// Extensions for the enum class.
///</summary>publicstaticclass EnumExtensions
{
///<summary>/// Gets the description of an enumeration.
///</summary>///<paramname="me">The enumeration.</param>///<returns>The value of the [Description] attribute for the enum, or the name of
/// the enum value if there isn't one.</returns>publicstaticstring GetDescription(this Enum me)
{
// Get the enum type.
var enumType = me.GetType();
// Get the description attribute.
var descriptionAttribute = enumType.GetField(me.ToString())
.GetCustomAttributes(typeof(DescriptionAttribute), false)
.FirstOrDefault() as DescriptionAttribute;
// Get the description (if there is one) or the name of the enum otherwise.
return descriptionAttribute != null
? descriptionAttribute.Description
: me.ToString();
}
}

We've done it! We can now use our EnumerationComboBox like this:

<!-- The combo box, bound to an enumeration. --><apexControls:EnumerationComboBoxSelectedEnumeration="{Binding Character}"/>

And it all works! Very easy to use in the future, and no ObjectDataSource to worry about!

I do think that one of the great things about C#/WPF is the fact that you have so many options when looking at things like this - it's a bit corny sounding but it really is almost the case that if you can imagine it you can do it. I just hope MS keep working on WPF and pushing it - I have a fear that they may try to drive HTML5/JS ahead of WPF, I think that WPF could have a very important place in modern day software development

Inheritance these days bugs me. A lot of times I've had to return to code to rework because of inheritance problems. I think this is a very good explanation and solution, but I've made one that fits into a behaviour.

Glad you like it - I know exactly what you mean about the inheritance thing, I was very much on the fence about whether or not to make it a behaviour. In the end for the purposes of clarity I used a derived class so that those unfamiliar with behaviours would be able to follow it, although what you've done is great because it's always good to have a choice of approaches!