Library code snippets

Binding a Control to an Enum

Imagine you have an enum defined in your code like so:

enum ContractType
{
    Permanent = 1,
    Contract = 2,
    Internship = 99
}

Suppose we have a DropDownList on an ASP.NET page from which we'd like the user to select the appropriate ContractType.

<asp:DropDownList runat="server" DataTextField="Key" DataValueField="Value" id="MyDropDownList">

Obviously, we can't do something as simple as

MyDropDownList.DataSource = ContractType;

as ContractType is a type, not an object. Instead, we can create a simple helper function that uses the Enum.GetValues and Enum.GetNames methods in order to create a Hashtable object (consisting of keys - Permanent, Contract, etc, and values - 1, 2 etc).

public static Hashtable BindToEnum(Type enumType)
{
    // get the names from the enumeration
    string[] names = Enum.GetNames(enumType);
    // get the values from the enumeration
    Array values = Enum.GetValues(enumType);
    // turn it into a hash table
    Hashtable ht = new Hashtable();
    for (int i = 0; i < names.Length; i++)
        // note the cast to integer here is important
        // otherwise we'll just get the enum string back again
        ht.Add(names[i], (int)values.GetValue(i));
    // return the dictionary to be bound to
    return ht;
}

You can then use this as follows:

MyDropDownList.DataSource = BindToEnum(typeof(ContractType));

and we get a drop down list bound to the appropriate names/values as defined by the enum (note that we specified DataTextField and DataValueField in the earlier DropDownList definition).

Comments

  1. 07 Aug 2007 at 14:11

    Why not just use:

    MyDropDownList.DataSource = Enum.GetNames(typeof(ContractType));

  2. 22 Feb 2007 at 17:43
    I am binding an ASP.net control using the above methods. For some reason each of the item in dropdownlist is showing System.Collections.DictionaryEntry as text and value, although I checked the key value pair in hash table and it has same values as enum. Makes me wonder what happens during databinding? How can I get the right sat of text and value in my dropdown list? Any idea?
  3. 07 Dec 2006 at 18:17

    In order to be able to sort you will have to implement an instance of the icomparer. 

    The first change is to the "BindToEnum" function:

    Private

    Function BindToEnum(ByVal enumType As Type) As ArrayList()

    Dim names As String(), values As Array

    Dim x As Integer = 0

    names = System.Enum.GetNames(enumType)

    values = System.Enum.GetValues(enumType)

    Dim arrayOfEnum(names.Length - 1) As HW.ArraySort

    While x < names.Length

    arrayOfEnum(x) =

    New HW.ArraySort(CType(values.GetValue(x), Integer), names(x))

    x = x + 1

    End While

    Array.Sort(arrayOfEnum)

    Return arrayOfEnum

    End Function

     

    You will now be returning an ArrayList.  You will also need to add the following code in a module file:

    Option

    Explicit On

    Option

    Strict On

    Imports

    System.Collections

    Public

    Class ArraySort : Inherits System.Collections.ArrayList : Implements IComparable

    ' Nested classes to do secondary sorts

    Private Class sortByValueAscendingHelper : Implements IComparer

    Function Compare(ByVal a As Object, ByVal b As Object) As Integer Implements IComparer.Compare

    Dim c1 As ArraySort = CType(a, ArraySort)

    Dim c2 As ArraySort = CType(b, ArraySort)

    If (c1.Value > c2.Value) Then

    Return 1

    End If

    If (c1.Value < c2.Value) Then

    Return -1

    Else

    Return 0

    End If

    End Function

    End Class

    Private Class sortByValueDescendingHelper : Implements IComparer

    Function Compare(ByVal a As Object, ByVal b As Object) As Integer Implements IComparer.Compare

    Dim c1 As ArraySort = CType(a, ArraySort)

    Dim c2 As ArraySort = CType(b, ArraySort)

    If (c1.Value < c2.Value) Then

    Return 1

    End If

    If (c1.Value > c2.Value) Then

    Return -1

    Else

    Return 0

    End If

    End Function

    End Class

    Private Class sortKeyDescendingHelper : Implements IComparer

    Function Compare(ByVal a As Object, ByVal b As Object) As Integer Implements IComparer.Compare

    Dim c1 As ArraySort = CType(a, ArraySort)

    Dim c2 As ArraySort = CType(b, ArraySort)

    Return String.Compare(c2.mKey, c1.mKey)

    End Function

    End Class

    ' End nested classes.

    Private mValue As Integer

    Private mKey As String

    Public Sub New(ByVal Value As Integer, ByVal Key As String)

    mKey = Key

    mValue = Value

    End Sub

    Public Property Value() As Integer

    Get

    Return mValue

    End Get

    Set(ByVal Value As Integer)

    mValue = Value

    End Set

    End Property

    Public Property Key() As String

    Get

    Return mKey

    End Get

    Set(ByVal Value As String)

    mKey = Value

    End Set

    End Property

    Function CompareTo(ByVal obj As Object) As Integer Implements IComparable.CompareTo

    Dim c As ArraySort = CType(obj, ArraySort)

    Return String.Compare(Me.mKey, c.mKey)

    End Function

    Public Shared Function sortByValueAscending() As IComparer

    Return CType(New sortByValueAscendingHelper, IComparer)

    End Function

    Public Shared Function sortByValueDescending() As IComparer

    Return CType(New sortByValueDescendingHelper, IComparer)

    End Function

    Public Shared Function sortByKeyDescending() As IComparer

    Return CType(New sortKeyDescendingHelper, IComparer)

    End Function

    End

    Class

    Now you are able to sort by KEY (display data) or Value either ascending or descending.

    Hopefully this solves your issue..

  4. 06 Dec 2006 at 18:17

    Good Post!!

    Just wanted to make an additional comment.

    By changing the following lines:

    Dim names As String() = ContractType.GetNames(enumType) 
    Dim values As Array = ContractType.GetValues(enumType)

    TO:

     Dim names As String() = System.Enum.GetNames(enumType)

     Dim values As Array = System.Enum.GetValues(enumType)

    You make this process reusable.

  5. 13 Jan 2006 at 07:30

    Using Hashtable it is not possible.


    Instead of HashTable use an ArrayList


    ht=new ArrayList();
    And change the code like this.


    ht.Insert((int)values.GetValue(i),names);


    No need to specify the DataTextField and DataValueField of the Dropdownlist



  6. 10 Jan 2006 at 06:39

     When we bind the Hashtable to the DropDown the list get the values in a random order?
    How do i resolve this .
       Suppose my list contains days,then
    I want my days to be displayed in the order for eg. Sunday - Saturday...


     

  7. 21 Oct 2005 at 22:53

    ehh. I'm trying to make the public shared sub general by passing in the enum as a parameter. I'm having trouble. Is this not possible?

  8. 22 Sep 2005 at 18:57

    If you just want the names, and don't need the values, you could just do:


    list.DataSource = System.Enum.GetNames(typeof(MyEnum));


    There's probably a trick to using GetNames and GetValues to quickly get what you need without having to loop over the enum.

  9. 04 Aug 2005 at 07:34

    ah yes.. of course... thanks

  10. 04 Aug 2005 at 07:06

    yes
    u will get that error if u r using windows form in windows form


    u can use a datatable instead


      Private Enum ContractType
          Permanent = 1
          Contract = 2
          Internship = 99
      End Enum
      Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
       
          ComboBox1.DataSource = BindToEnum(GetType(ContractType))
          ComboBox1.DisplayMember = "Key"
          ComboBox1.ValueMember = "Value"


      End Sub
      Public Shared Function BindToEnum(ByVal enumType As Type) As DataTable


          Dim names As String() = ContractType.GetNames(enumType)
          Dim values As Array = ContractType.GetValues(enumType)
          Dim dt As New DataTable
          dt.Columns.Add("Key", GetType(String))
          dt.Columns.Add("Value", GetType(Integer))


          Dim i As Integer = 0
          While i < names.Length
              Dim dr As DataRow = dt.NewRow
              dr("Key") = names(i)
              dr("Value") = CType(values.GetValue(i), Integer)
              dt.Rows.Add(dr)
              i = i + 1
          End While
          Return dt


      End Function


  11. 04 Aug 2005 at 05:15

    Thanks man

  12. 31 Jul 2005 at 12:30
    Is it posible to do something similar in a Windows Forms application?  I have tried the code in VB.NET and get an error that complex binding is not allowed... The DataSource must be an IList or IListSource...?

  13. 01 Jan 1999 at 00:00

    This thread is for discussions of Binding a Control to an Enum.

Leave a comment

Sign in or Join us (it's free).

James Crowley James first started this website when learning Visual Basic back in 1999 whilst studying his GCSEs. The site grew steadily over the years while being run as a hobby - to a regular monthly audience ...

Related podcasts

Events coming up

  • Mar 15

    DevWeek 2010

    London, United Kingdom

    DevWeek is Europe’s leading independent conference for software developers, database professionals and IT architects, and features expert speakers on a wide range of topics, including .NET 4.0, Silverlight 3, WCF 4, Visual Studio 2010, REST, Windows Workflow 4, Thread Synchronization, ASP.NET 4.0, SQL Server 2008 R2, LINQ, Unit Testing, CLR & C# 4.0, .NET Patterns, WPF 4, F#, Windows Azure, ADO.NET, Entity Framework, Debugging, T-SQL Tips & Tricks, and more.

Want to stay in touch with what's going on? Follow us on twitter!