Wednesday, June 08, 2011

Binding an Enum to a DataSource

I had some code for an ASP.Net Webforms app where I need to present to the user a list of options that were define as Enum.  I want to populate a combobox with the enumerated type values and do it from code automatically.  This is the Enum in question

enum PrintColorSchema {
Default = 0,
FullColor = 1,
GrayScale = 2,
BlackAndWhite = 3,
}


To make things more interesting, I wanted to exclude the first item in the list, “Default”.  One way to do this would be to manually populate a select list with the values from the Enum.  While that would work for this Enum, I wanted to find a way where I didn’t have to hard code the values.

I added a DropDownList control to the page and in the code behind, I added the following code:

ColorSchema.DataSource = 
Enum.GetValues(typeof(PrintColorSchema))
.Cast<PrintColorSchema>()
.Select(en => new
{
Value = en,
Text = Wordify(en.ToString())
}).Where (en => en.Value != PrintColorSchema.Default);

ColorSchema.DataTextField = "Text";
ColorSchema.DataValueField = "Value";
ColorSchema.DataBind();

What we are using is a bit of LINQ to convert the Enum to an IEnumerable collection of an anonymous class. That class has two members, Value and Text. Value is set to the enumerated type and Text is set to prettified version of the enumerated type. That function looks like this:

public static string Wordify(string pascalCaseString)
{
System.Text.RegularExpressions.Regex r =
new System.Text.RegularExpressions.Regex("(?<=[a-z])(?[A-Z])|(?<=.)(?[A-Z])(?=[a-z])");
return r.Replace(pascalCaseString, " ${x}");
}

The code

Enum.GetValues(typeof(PrintColorSchema))

converts the Enum to an array of constants. The next part

.Cast<PrintColorSchema>()

returns an IEnumerable collecttion from the array. The code

.Select(en => new
{
Value = en,
Text = Wordify(en.ToString())
})

returns a new IEnumerable<> collection of an anonymouse type. That type has the enumeration element as the Value and that element converted to a string as the Text. Since the elements were in "PascalCase", a simple RegEx function was used to split the text into multiple words, The final Where operator is used to filter out the first item from the list.

The HTML that gets rendered:

<select id="ColorSchema" name="ColorSchema"> 
<option selected value="FullColor">Full Color</option>
<option value="GrayScale">Gray Scale</option>
<option value="BlackAndWhite">Black And White</option>
</select>

Which renders like this



For this Enum, all the code was overkill, adding three <option> elements to the <select> control would have been less work.  Where this is handy is when you have Enum types with many elements or when the Enum type changes.  If the Enum type changes, no modification to your code is needed to update the combo box.  One less place in the code to fail.  And that is a good thing.