A Custom DropDownList using an Enum Type as a DataSource

First off, I have to again express my admiration at the job Microsoft have done at building the core ASP.NET Web Form Controls.  I think they are sometimes taken for granted. 

This post is about making a control which derives from the DropDownList and uses a Enum as a Data Source.  A little more though, you can transform the text with the use of Regular Expressions.  I had a scenario where by I need a static set of Enum Values in the database to correspond with foreign keys in another table.  So for example, say you have a table called Cars and it has a TransmissionID field which is linked to another table called TransmissionType. 

TransmissionType

TransmissionTypeID

TransmissionTypeName

The values for exmaple in this table could be Manual Drive, Automatic Drive.  Now, I know that these values will not change, and the point is made stronger when the number of types is great and static or will not be changed that often at all.  So that I can communicate these values back to the database and take advantage of the C# Enum Type I create an Enum called TransmissionType.

pubilc enum TransmissionType{
	ManualDrive = 1,
	AutomaticDrive = 2
}

Notice the format of the text between the enum names and the table fields i.e. Enum is CamelCase and the field values have a space to make good language and sense.  Now I want to assign this enum as the DataSource to a DropDownList and even more than that I want the actual value of the enum to be the value of the ListItems in the DropDownList.

You can simply bind a list of Enums to a DropDownList and it will render but will not contain the value of each of the Enum Names, assuming you have values.  I simply created a quick ASP.NET Server Control, derived it from the DropDownList and added a few more bits:

1. Define a private collection of ListItems

private ListItemCollection collection;
 

2. Define a custom property in the control called EnumType

        [Bindable(true)]
        [Category("Behaviour")]
        [Localizable(false)]
        public string EnumType
        {
            get
            {
                String s = (String)ViewState["EnumType"];
                return ((s == null) ? String.Empty : s);
            }

            set
            {
                ViewState["EnumType"] = value;
            }
        }

3. Define a custom property in the control called TextTransaformationPattern

        [Bindable(true)]
        [Category("Behaviour")]
        [Localizable(false)]
        [DefaultValue("[A-Z]")]
        public string TextTransaformationPattern
        {
            get
            {
                String s = (String)ViewState["TextTransaformationPattern"];
                return ((s == null) ? String.Empty : s);
            }

            set
            {
                ViewState["TextTransaformationPattern"] = value;
            }
        }

4. Define a custom property in the control called TextTransaformationReplacement

        [Bindable(true)]
        [Category("Behaviour")]
        [Localizable(false)]
        [DefaultValue(" $0")]
        public string TextTransaformationReplacement
        {
            get
            {
                String s = (String)ViewState["TextTransaformationReplacement"];
                return ((s == null) ? String.Empty : s);
            }

            set
            {
                ViewState["TextTransaformationReplacement"] = value;
            }
        }

 

5.Instantiate the collection in the OnInit Event Handler, add the List Items whilst formatting the names to give a slightly better effect and also enabling the value of the enum to go into the value of the ListItem.

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            collection = new ListItemCollection();

            foreach (string s in Enum.GetNames(Type.GetType(EnumType)))
            {
                ListItem li = new ListItem(
                    Regex.Replace(s, TextTransaformationPattern, TextTransaformationReplacement),
                    ((int)Enum.Parse(Type.GetType(EnumType), s)).ToString());
                collection.Add(li);
            }
        }

6.Override the ListItemCollection getter and return our new list of ListItems.

        public override ListItemCollection Items
        {
            get
            {
                return collection;
            }
        }

The need for the regular expressions is just one way I came up with to format the text in a way which avoided the Camel Case look.  In the regular expression replace I simply tell it to replace the Matched Element with a space and the Matched Element i.e. $0 so CamelCase becomes Camel Case.  Probably better to trim the string also to take away the first space, but anyway you get the idea.  Implementation includes using the AssemblyQualifiedName i.e. "MyNameSpace.Type, MyAssembly."  An example implementation is below:

<aebs:EnumDropDownList ID="EnumDropDownList1" runat="server" 
            EnumType="uk.co.andrewrea.commerce.DeliveryMethod,uk.co.andrewrea.commerce"
            TextTransaformationReplacement=" $0"
            TextTransaformationPattern="[A-Z]">
            </aebs:EnumDropDownList>

 

I am sure you could cache the values to make better for performance but it was a nice fix for some of the FormView Elements I am working with.  You can also enable the DropDownList to work with the Bind method in mark up by say creating a Property which gets and sets the selectedValue property of the DropDownList and use the Bind Method there.  I will modify the control and make another post about using the DropDownList and the Bind within say a FormView next. 

 

image

This is based on the following Enum:

    public enum InventoryStatus
    {
        InStock = 1,
        BackOrder = 2,
        PreOrder = 3,
        SpecialOrder = 4,
        Discontinued = 5,
        CurrentlyUnavailable = 6
    }

The output in html is then the following:

InventoryStatus:
  
<select name="ctl00$ContentPlaceHolder1$FormView1$ddlInventoryStatus" 
id="ctl00_ContentPlaceHolder1_FormView1_ddlInventoryStatus">
  
<option selected="selected" value="1"> In Stock</option>
  
<option value="2"> Back Order</option>
  
<option value="3"> Pre Order</option>
  
<option value="4"> Special Order</option>
  
<option value="5"> Discontinued</option>
  
<option value="6"> Currently Unavailable</option>
  
  
</select>

 

Here is the full code:

Cheers,


Andrew

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text.RegularExpressions;

namespace uk.co.andrewrea.web.ui.control
{
    [DefaultProperty("Value")]
    [ToolboxData("<{0}:EnumDropDownList runat=server></{0}:EnumDropDownList>")]
    public class EnumDropDownList : DropDownList
    {
        private ListItemCollection collection;


        [Bindable(true)]
        [Category("Appearance")]
        [DefaultValue("")]
        [Localizable(true)]
        public string Value
        {
            get
            {
                String s = (String)ViewState["Value"];
                return ((s == null) ? String.Empty : s);
            }

            set
            {
                ViewState["Value"] = value;
            }
        }

        [Bindable(true)]
        [Category("Behaviour")]
        [Localizable(false)]
        public string EnumType
        {
            get
            {
                String s = (String)ViewState["EnumType"];
                return ((s == null) ? String.Empty : s);
            }

            set
            {
                ViewState["EnumType"] = value;
            }
        }

        [Bindable(true)]
        [Category("Behaviour")]
        [Localizable(false)]
        [DefaultValue("[A-Z]")]
        public string TextTransaformationPattern
        {
            get
            {
                String s = (String)ViewState["TextTransaformationPattern"];
                return ((s == null) ? String.Empty : s);
            }

            set
            {
                ViewState["TextTransaformationPattern"] = value;
            }
        }

        [Bindable(true)]
        [Category("Behaviour")]
        [Localizable(false)]
        [DefaultValue(" $0")]
        public string TextTransaformationReplacement
        {
            get
            {
                String s = (String)ViewState["TextTransaformationReplacement"];
                return ((s == null) ? String.Empty : s);
            }

            set
            {
                ViewState["TextTransaformationReplacement"] = value;
            }
        }

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            collection = new ListItemCollection();

            foreach (string s in Enum.GetNames(Type.GetType(EnumType)))
            {
                ListItem li = new ListItem(
                    Regex.Replace(s, TextTransaformationPattern, TextTransaformationReplacement),
                    ((int)Enum.Parse(Type.GetType(EnumType), s)).ToString());
                collection.Add(li);
            }
        }

        public override ListItemCollection Items
        {
            get
            {
                return collection;
            }
        }
    }
}
Published Monday, November 03, 2008 10:31 PM by REA_ANDREW

Comments

# Pages tagged "cheers"

Tuesday, November 04, 2008 12:21 AM by Pages tagged "cheers"

Pingback from  Pages tagged "cheers"

# rascunho &raquo; Blog Archive &raquo; links for 2008-11-05

Wednesday, November 05, 2008 3:11 PM by rascunho » Blog Archive » links for 2008-11-05

Pingback from  rascunho  &raquo; Blog Archive   &raquo; links for 2008-11-05

# 2008 November 06 - Links for today &laquo; My (almost) Daily Links

Thursday, November 06, 2008 4:00 AM by 2008 November 06 - Links for today « My (almost) Daily Links

Pingback from  2008 November 06 - Links for today &laquo; My (almost) Daily Links

Leave a Comment

(required) 
(required) 
(optional)
(required)