Enum: Binding to the Description Attribute
Posted
Fri, Jul 10 2009 16:31
by
Deborah Kurata
The Enum keyword allows you to define a standard set of named constants for use in your application. Sometimes you may want to present this same list of values to your user.
You can display the set of Enum values in a ComboBox or ListBox using data binding. And even better, if you use the DescriptionAttribute in the Enum, you can display a more user-friendly set of values.
For example, a Customer business object may have a CustomerType defined with a specific set of options for corporations, individuals, schools, and charities. You want to use these values in your code, but also display them to the user in a ComboBox.
Enum Definition
The Enum can reside in the Customer class, or in its own class.
In C#:
public enum CustomerTypeOption
{
NotDefined,
Corp,
IndividualorFamily,
SchoolorUniversity,
Charity
}
In VB:
Public Enum CustomerTypeOption
NotDefined
Corp
IndividualorFamily
SchoolorUniversity
Charity
End Enum
CustomerType Property
A CustomerType property in the Customer class can use this enum type.
In C#:
public CustomerTypeOption CustomerType { get; set; }
In VB:
Private _CustomerType As CustomerTypeOption
Public Property CustomerType() As CustomerTypeOption
Get
Return _CustomerType
End Get
Set(ByVal value As CustomerTypeOption)
_CustomerType = value
End Set
End Property
The C# code uses the automatically implemented properties feature introduced with .NET 3.5. The VB code uses the full property definition.
Binding To an Enum
The Enum can also be used by the user interface. For example, you can bind a comboBox or listBox to a set of customer type options.
In C#:
Dictionary<string, int> CustomerTypeList =
new Dictionary<string, int>();
foreach (int enumValue in
Enum.GetValues(typeof(Customer.CustomerTypeOption)))
{
CustomerTypeList.Add(
Enum.GetName(typeof(Customer.CustomerTypeOption),
enumValue ), enumValue);
}
// Bind the customer type combo box
CustomerTypeComboBox.DisplayMember = "Key";
CustomerTypeComboBox.ValueMember = "Value";
CustomerTypeComboBox.DataSource = new BindingSource(CustomerTypeList,
null);
In VB:
Dim CustomerTypeList As New Dictionary(Of String, Integer)
For Each enumValue As Integer In _
[Enum].GetValues(GetType(Customer.CustomerTypeOption))
CustomerTypeList.Add( _
[Enum].GetName(GetType(Customer.CustomerTypeOption), _
enumValue), enumValue)
Next
' Bind the combo box
CustomerTypeComboBox.DisplayMember = "Key"
CustomerTypeComboBox.ValueMember = "Value"
CustomerTypeComboBox.DataSource = New BindingSource(CustomerTypeList, _
Nothing)
This code defines a Dictionary to contain the name of the enum and the integer value of the enum. The for/each loop iterates through the set of Enum values and adds the name and value to the dictionary.
The code then binds to the ComboBox, setting the DisplayMember to the “Key” of the dictionary and the ValueMember to the “Value” of the Dictionary.
The result looks like this:
While it does provide the appropriate options, it is not very user-friendly. It would be nicer if there were appropriate spaces and full words. For that, you can use the DescriptionAttribute on the Enum.
Using the DescriptionAttribute
NOTE: Be sure to import the System.ComponentModel and the System.Reflection namespaces.
In C#:
public enum CustomerTypeOption
{
[DescriptionAttribute("Not Specified")]
NotDefined,
[DescriptionAttribute("Corporation")]
Corp,
[DescriptionAttribute("Individual or Family")]
IndividualorFamily,
[DescriptionAttribute("School or University")]
SchoolorUniversity,
[DescriptionAttribute("Charity")]
Charity
}
In VB:
Public Enum CustomerType
<DescriptionAttribute("Corporate Customer")> _
CorpCustomer
<DescriptionAttribute("Individual or Family")> _
IndividualorFamily
<DescriptionAttribute("School or University")> _
SchoolorUniversity
<DescriptionAttribute("Charity")> _
Charity
<DescriptionAttribute("Kingdom")> _
Kingdom
End Enum
Binding to an Enum Description
Now you can bind to the description instead of to the Enum constant.
In C#:
Dictionary<string, int> CustomerTypeList =
new Dictionary<string, int>();
FieldInfo fi;
DescriptionAttribute da;
foreach (Customer.CustomerTypeOption enumValue in
Enum.GetValues(typeof(Customer.CustomerTypeOption)))
{
fi = typeof(Customer.CustomerTypeOption).
GetField((enumValue.ToString()));
da = (DescriptionAttribute)Attribute.GetCustomAttribute(fi,
typeof(DescriptionAttribute));
if (da != null)
{
CustomerTypeList.Add(da.Description, (int)enumValue);
}
}
// Bind the customer type combo box
CustomerTypeComboBox.DisplayMember = "Key";
CustomerTypeComboBox.ValueMember = "Value";
CustomerTypeComboBox.DataSource = new BindingSource(CustomerTypeList,
null);
In VB:
Dim CustomerTypeList As New Dictionary(Of String, Integer)
Dim fi As FieldInfo
Dim da As DescriptionAttribute
For Each enumValue As Customer.CustomerTypeOption In _
[Enum].GetValues(GetType(Customer.CustomerTypeOption))
fi = GetType(Customer.CustomerTypeOption). _
GetField(enumValue.ToString)
da = DirectCast(Attribute.GetCustomAttribute(fi, _
GetType(DescriptionAttribute)), DescriptionAttribute)
If da IsNot Nothing Then
CustomerTypeList.Add(da.Description, enumValue)
End If
Next
' Bind the combo box
CustomerTypeComboBox.DisplayMember = "Key"
CustomerTypeComboBox.ValueMember = "Value"
CustomerTypeComboBox.DataSource = New BindingSource(CustomerTypeList, _
Nothing)
This code defines a Dictionary to contain the description of the enum and the integer value of the enum. The for/each loop iterates through the set of Enum values. It uses reflection to find the DescriptionAttribute. It then adds the description and value to the dictionary.
The code then binds to the ComboBox, setting the DisplayMember to the “Key” of the dictionary and the ValueMember to the “Value” of the Dictionary.
Now the combo box looks like this:
Much better!
Extension Methods
So the user interface looks nicer, but the code to get the DescriptionAttribute looks rather tedious. It would be much nicer if there was a GetDescription method on the Enum. But hey, with the extension method feature introduced in .NET 3.5, we can build one ourselves!
In C#:
public static string GetDescription(this Enum currentEnum)
{
string description = String.Empty;
DescriptionAttribute da ;
FieldInfo fi = currentEnum.GetType().
GetField(currentEnum.ToString());
da = (DescriptionAttribute)Attribute.GetCustomAttribute(fi,
typeof(DescriptionAttribute));
if (da != null)
description = da.Description;
else
description = currentEnum.ToString();
return description;
}
In VB:
<ExtensionAttribute()> _
Public Function GetDescription(ByVal currentEnum As [Enum]) As String
Dim description As String = String.Empty
Dim da As DescriptionAttribute
Dim fi As FieldInfo = currentEnum.GetType. _
GetField(currentEnum.ToString)
da = DirectCast(Attribute.GetCustomAttribute(fi, _
GetType(DescriptionAttribute)), DescriptionAttribute)
If da IsNot Nothing Then
description = da.Description
Else
description = currentEnum.ToString
End If
Return description
End Function
The C# code can reside in any static class. The VB code must reside in a module, which provides the same features as a static class.
This code uses reflection to get the DescriptionAttribute for any Enum value. So it can be readily reused. The code returns the DescriptionAttribute if one is found, otherwise it returns the name.
Binding to an Enum Description - Redux
Now the binding code is much easier to work with.
In C#:
Dictionary<string, int> CustomerTypeList =
new Dictionary<string, int>();
foreach (Customer.CustomerTypeOption enumValue in
Enum.GetValues(typeof(Customer.CustomerTypeOption)))
{
CustomerTypeList.Add(enumValue.GetDescription(), (int)enumValue);
}
// Bind the customer type combo box
CustomerTypeComboBox.DisplayMember = "Key";
CustomerTypeComboBox.ValueMember = "Value";
CustomerTypeComboBox.DataSource = new BindingSource(CustomerTypeList,
null);
In VB:
Dim CustomerTypeList As New Dictionary(Of String, Integer)
For Each enumValue As Customer.CustomerTypeOption In _
[Enum].GetValues(GetType(Customer.CustomerTypeOption))
CustomerTypeList.Add(enumValue.GetDescription, enumValue)
Next
' Bind the combo box
CustomerTypeComboBox.DisplayMember = "Key"
CustomerTypeComboBox.ValueMember = "Value"
CustomerTypeComboBox.DataSource = New BindingSource(CustomerTypeList, _
Nothing)
Enjoy!