Deborah's Developer MindScape






         Tips and Techniques for Web and .NET developers.

Archive for Data Binding

July 10, 2009

Enum: Binding to the Description Attribute

Filed under: C#,Data Binding,VB.NET,WinForms @ 6:31 pm

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:

image

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:

image

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!

« Previous Page

© 2021 Deborah's Developer MindScape   Provided by WPMU DEV -The WordPress Experts   Hosted by Microsoft MVPs