|
|||||||||||||||||||||
|
|||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionEvery once in a while I need to bind an enumerated type to a Windows Forms control, usually a The Simple WayThe simplest is to use the public enum SimpleEnum
{
Today,
Last7
Last14,
Last30,
All
}
You can bind it to a ComboBox combo = new ComboBox();
combo.DataSource = Enum.GetValues(typeof(SimpleEnum));
While this does work, there are a couple of problems:
Binding with DescriptionsFortunately, there is a relatively easy way to meet these requirements using a little bit of Reflection and decorating the enum values with an attribute. You don't need a lot of generic classes, custom classes, or custom type descriptors...just two static methods that are both less than 10 lines of code. The first step is to add a description attribute to your enum. For simplicity, you can use the /// <summary>
/// Provides a description for an enumerated type.
/// </summary>
[AttributeUsage(AttributeTargets.Enum | AttributeTargets.Field,
AllowMultiple = false)]
public sealed class EnumDescriptionAttribute : Attribute
{
private string description;
/// <summary>
/// Gets the description stored in this attribute.
/// </summary>
/// <value>The description stored in the attribute.</value>
public string Description
{
get
{
return this.description;
}
}
/// <summary>
/// Initializes a new instance of the
/// <see cref="EnumDescriptionAttribute"/> class.
/// </summary>
/// <param name="description">The description to store in this attribute.
/// </param>
public EnumDescriptionAttribute(string description)
: base()
{
this.description = description;
}
}
Now that we have our description attribute, we need to decorate the enum with it: public enum SimpleEnum
{
[EnumDescription("Today")]
Today,
[EnumDescription("Last 7 days")]
Last7,
[EnumDescription("Last 14 days")]
Last14,
[EnumDescription("Last 30 days")]
Last30,
[EnumDescription("All")]
All
}
Using a custom attribute allows you to keep the human readable description in the code where the enum is defined. It also allows you to retrieve localized versions of the description. In order to do that, you simply need to change the way the attribute works to lookup the appropriate string in the string resources. The next part is what actually does all of the work. As I mentioned, both of these functions are less than 10 lines of code. The easiest way to work with these functions is to create a static (or sealed, if you aren't using .NET 2.0 or later) class that holds these two static functions. /// <summary>
/// Provides a static utility object of methods and properties to interact
/// with enumerated types.
/// </summary>
public static class EnumHelper
{
/// <summary>
/// Gets the <see cref="DescriptionAttribute" /> of an <see cref="Enum" />
/// type value.
/// </summary>
/// <param name="value">The <see cref="Enum" /> type value.</param>
/// <returns>A string containing the text of the
/// <see cref="DescriptionAttribute"/>.</returns>
public static string GetDescription(Enum value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
string description = value.ToString();
FieldInfo fieldInfo = value.GetType().GetField(description);
EnumDescriptionAttribute[] attributes =
(EnumDescriptionAttribute[])
fieldInfo.GetCustomAttributes(typeof(EnumDescriptionAttribute), false);
if (attributes != null && attributes.Length > 0)
{
description = attributes[0].Description;
}
return description;
}
/// <summary>
/// Converts the <see cref="Enum" /> type to an <see cref="IList" />
/// compatible object.
/// </summary>
/// <param name="type">The <see cref="Enum"/> type.</param>
/// <returns>An <see cref="IList"/> containing the enumerated
/// type value and description.</returns>
public static IList ToList(Type type)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
ArrayList list = new ArrayList();
Array enumValues = Enum.GetValues(type);
foreach (Enum value in enumValues)
{
list.Add(new KeyValuePair<Enum, string>(value, GetDescription(value)));
}
return list;
}
}
As you can see, the In order to bind the ComboBox combo = new ComboBox();
combo.DataSource = EnumHelper.ToList(typeof(SimpleEnum));
combo.DisplayMember = "Value";
combo.ValueMember = "Key";
.NET 3.5 Extension MethodsAs was pointed out in the article comments[^], it is very easy to convert the methods in To make the change to extension methods, you add the /// <summary>
/// Provides a static utility object of methods and properties to interact
/// with enumerated types.
/// </summary>
public static class EnumHelper
{
/// <summary>
/// Gets the <see cref="DescriptionAttribute" /> of an <see cref="Enum" />
/// type value.
/// </summary>
/// <param name="value">The <see cref="Enum" /> type value.</param>
/// <returns>A string containing the text of the
/// <see cref="DescriptionAttribute"/>.</returns>
public static string GetDescription(this Enum value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
string description = value.ToString();
FieldInfo fieldInfo = value.GetType().GetField(description);
EnumDescriptionAttribute[] attributes =
(EnumDescriptionAttribute[])
fieldInfo.GetCustomAttributes(typeof(EnumDescriptionAttribute), false);
if (attributes != null && attributes.Length > 0)
{
description = attributes[0].Description;
}
return description;
}
/// <summary>
/// Converts the <see cref="Enum" /> type to an <see cref="IList" />
/// compatible object.
/// </summary>
/// <param name="type">The <see cref="Enum"/> type.</param>
/// <returns>An <see cref="IList"/> containing the enumerated
/// type value and description.</returns>
public static IList ToList(this Type type)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
ArrayList list = new ArrayList();
Array enumValues = Enum.GetValues(type);
foreach (Enum value in enumValues)
{
list.Add(new KeyValuePair<Enum, string>(value, GetDescription(value)));
}
return list;
}
}
In order to bind the combo.DataSource = typeof(SimpleEnum).ToList();
Advanced UsesTo support additional advanced cases where the underlying numeric value is needed, you can use a generic version of the // .NET 2.0, 3.0
combo.DataSource = EnumHelper.ToList<int>(typeof(SimpleEnum));
// .NET 3.5
combo.DataSource = typeof(SimpleEnum).ToList<int>();
In addition, by using the // .NET 2.0, 3.0
combo.DataSource = EnumHelper.ToExtendedList<int>(typeof(SimpleEnum));
combo.DisplayMember = "Value";
combo.ValueMember = "Key";
// OR
combo.DataSource = EnumHelper.ToExtendedList<int>(typeof(SimpleEnum));
combo.DisplayMember = "Value";
combo.ValueMember = "NumericKey";
// .NET 3.5
combo.DataSource = typeof(SimpleEnum).ToExtendedList<int>();
combo.DisplayMember = "Value";
combo.ValueMember = "Key";
// OR
combo.DataSource = typeof(SimpleEnum).ToExtendedList<int>();
combo.DisplayMember = "Value";
combo.ValueMember = "NumericKey";
ConclusionYou now have a Revision History6-September-2007:
26-August-2007:
12-August-2007:
| ||||||||||||||||||||