WPF EnumComboBox UserControl
Introduction
In this article I will demonstrate a custom control that will allow you to display items from an enum in a combo box. I have a couple of requirements though.
-
The displayed values must be in human readable strings, numbers or the enum type would not do.
-
The implementation must be easily reusable.
Creating the EnumComboBox Control
First, create a class that will allow us to view the description of custom attributes.
public class EnumerateUtil
{
// Methods
private EnumerateUtil()
{
}
public static string GetDescription(Enum value)
{
DescriptionAttribute[] customAttributes = (DescriptionAttribute[]) value.GetType().GetField(value.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
return ((customAttributes.Length > 0) ? customAttributes[0].Description : value.ToString());
}
}
Next, create a new custom control, I called mine EnumComboBox.
public class EnumComboBox : System.Windows.Controls.ComboBox
{
static EnumComboBox()
{
//This OverrideMetadata call tells the system that this element wants to provide a style that is different than its base class.
//This style is defined in themes\generic.xaml
//DefaultStyleKeyProperty.OverrideMetadata(typeof(EnumComboBox), new FrameworkPropertyMetadata(typeof(EnumComboBox)));
}
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
FillItems();
}
private string _enumType;
[Browsable(true), Category("Data"), Description("Sets the fully qualified type of the enum to display in the DropDownList")]
public string EnumTypeName
{
get { return _enumType; }
set { _enumType = value; }
}
private List<KeyValuePair<int, string>> CachedValues
{
get
{
if (App.Current != null && App.Current.Properties != null)
{
return (List<KeyValuePair<int, string>>)App.Current.Properties["EnumComboBox_" + EnumTypeName];
}
else
{
return null;
}
}
set
{
if (App.Current != null && App.Current.Properties != null)
{
App.Current.Properties["EnumComboBox_" + EnumTypeName] = value;
}
}
}
private void FillItems()
{
List<KeyValuePair<int, string>> values = CachedValues;
if (values == null)
{
values = new List<KeyValuePair<int, string>>();
Type enumType = Type.GetType(EnumTypeName);
if (enumType == null)
{
throw new ArgumentException("Cannot load the type: " + EnumTypeName);
}
Array enumValues = Enum.GetValues(enumType);
for (int index = 0; index < enumValues.Length; index++)
{
int value = (int)enumValues.GetValue(index);
Enum enumValue = (Enum)enumValues.GetValue(index);
values.Add(new KeyValuePair<int, string>(value, EnumerateUtil.GetDescription(enumValue)));
}
CachedValues = values;
}
this.ItemsSource = values;
this.DisplayMemberPath = "Value";
this.SelectedValuePath = "Key";
}
}
Note, I commented the OverrideMetadata style property in the constructor. This is because, I want to apply my template on a control by control basis.Finally, create your enum and use description attributes to specify the visible string.
public enum TestType
{
[Description("Object One"), EnumMember]
ObjectOne = 1
,
[Description("Object Two"), EnumMember]
ObjectTwo = 2
}
Declaring the EnumComboBox
Now all we need to do is point the EnumTypeName property to the Entity that we will use to fill the combo box values.
<customControls:EnumComboBox EnumTypeName="YourNamespace.TestType, YourNamespace"/>
Conclusion
In this article I demonstrated using Description attributes and custom controls to create a combobox that will fill with human readable strings. Hopefully you found this useful.
Please feel free to leave comments or suggestions.
Very informative stuff. I as well have been working on an engine (http://www.codeplex.com/quickstartengine), however it takes a lot of dedication to explain in detail all of your work. Good job so far.
Nice. You could suggest a method of data binding. I struggled with this until I tried binding to the text member, e.g.
This worked. Thanks.