Click here to Skip to main content
Click here to Skip to main content

WPF EnumComboBox

, 18 Jun 2012
Rate this:
Please Sign up or sign in to vote.
A WPF comboBox for two-way binding of enumerations, showing localized descriptions for the enum values

Background

Selecting a value from an enumeration of appropriate values is a common task. A ComboBox is a well suited GUI element for that purpose. The ComboBox shows textual representations of all available values.

How do we get "nice" texts? A simple solution is the use of friendly names for the values, as does e.g. System.Drawing.Color[^] . But there is a drawback: a name must not contain white space (e.g. "Dark Blue" was changed to "DarkBlue").

A more advanced solution uses the Description attribute[^]. A converter, e.g. Description Enum TypeConverter[^], is used for the conversions from the value to the string and vice versa. Also a converter implementing WPF’s IValueConverter interface is available: Using DescriptionAttribute for enumerations bound to a ComboBox[^] .

When it comes to localization, things become more complicated. Most examples on the web only show how to get localized strings into the ComboBox, but omit the step from a user selection back to the enum value. Only Sacha Barber’s great article Binding and Using Friendly Enums in WPF[^] shows how to do a two-way binding.

I found his solution too verbose:

  • every enum value has to be decorated with a "LocalizableDescription" attribute, and there the enum’s name is repeated, and the name of the resource.
  • An ObjectDataProvider has to be created whenever such an enum is used – the information gets split up between the definition of the enum in a cs file, the localized strings in the resx files, and the ObjectDataProvider in a xaml file…

Translating the enum value to string (and vice versa)

The Enum Description Converter

This component asks a ResourceManager to get the localized string for the resource’s name. To keep things easy, the function "CreateResourceName" returns the enum value’s name – you could change that function if you want to include e.g. the TypeName of the enum or also its namespace.

If no ResourceManager is available, or if it did not return a value, the converter falls back to the Description attribute, and if that does not help, it returns the name of the value.

But how do we get that ResourceManager into the converter? Well, there’s a trick:

The ResourceAttribute

I created a new Attribute to connect an enumeration to a Resource. Just add the name of the resource when you set the attribute:

[ResourceAttribute("BusinessLogic.NumberResource")]
public enum SimpleNumbers 

When the converter is instantiated with the Type of the enumeration as a parameter, the ResourceAttribute is retrieved by reflection. Then the ResourceManager can be created. It is important to check here that the ResourceManager is valid – a typo in the resource name will not cause an exception in the constructor, only later on when a value has to be retrieved. That can be achieved by invoking the GetResourceSet method.

The EnumComboBox

This class derives from ComboBox and does all the translation magic with the enum description converter. When its EnumTypeName property is set, it retrieves the Type of the enumeration, and creates its internal enum description converter. It sets its ItemsSource to the list of translations returned from the converter. That is, internally this ComboBox works with a list of strings.

For binding a value, a new DependencyProperty is added: the SelectedEnumValue property. When a user selects a different value from the ComboBox, an overridden OnSelectionChanged method translates the description of the newly selected value to the enum value and sets the value of the dependency property. The PropertyChangedCallback method updates the text of the ComboBox when the bound value changes for other reasons.

Now it is easy to use the EnumComboBox in xaml:

<Utilities:EnumComboBox Height="25" HorizontalAlignment="Left" Margin="27,57,0,0" 
        Name="comboNumber" VerticalAlignment="Top" Width="230" 
        EnumTypeName="BusinessLogic.SimpleNumbers, BusinessLogic"
        SelectedEnumValue="{Binding ANumber}"/>

The Sample Code

I was not very creative when I coded the enumeration: it only lists numbers from 0 to 10. The enumeration is stored in the BusinessLogic.dll, and there are also the resource files with the translations, and a TestClass. The ResourceAttribute and the EnumComboBox along with its dependencies are in Utilities.dll.

The main sample references both projects. There is a simple main window for choosing a language. When you click on "Go", the CurrentCulture and CurrentUICulture of the CurrentThread are set. The next window is bound to the TestViewModel which relies on the TestClass. In the ComboBox, you see the names of the numbers in the selected language. "Show enum name" shows the name of the selected value. The selected value can also be changed by code: click on "Change number to Num_1" to set the value to Num_1.

And for our Indian friends: Yes, of course, this works also with Indian languages – see the Hindi example. And when you have to deal with right-to-left (e.g. Urdu), set the FlowDirection of the corresponding FrameworkElement, as shown with the Hebraic example.

Remaining issues

The SelectedItem and SelectedValue properties are still available and could cause confusion. I tried to overwrite the SelectedItem property, even with a "new" keyword, but that did not work.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Bernhard Hiller
Software Developer (Senior)
Germany Germany
No Biography provided

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Mobile
Web02 | 2.8.140827.1 | Last Updated 18 Jun 2012
Article Copyright 2012 by Bernhard Hiller
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid