Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET databinding a combobox to a string enum with Description attributes

I have an enum like this:

public enum Cities
{
    [Description("New York City")]
    NewYork,
    [Description("Los Angeles")]
    LosAngeles,
    Washington,
    [Description("San Antonio")]
    SanAntonio,
    Chicago
}

I want to bind this to a combobox and I've tried this:

comboBox.DataSource = Enum.GetNames(typeof(Cities));

But that displays the values in the combobox rather than the String description. So I switched to this:

public static string GetEnumDescription(Enum value)
{
    FieldInfo fi = value.GetType().GetField(value.ToString());

    DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);

    if (attributes != null && attributes.Length > 0)
    {
        return attributes[0].Description;
    }
    else
    {
        return value.ToString();
    }
}

public static IList ToList(this Type type)
{
    ArrayList list = new ArrayList();
    Array enumValues = Enum.GetValues(type);

    foreach (Enum value in enumValues)
    {
        list.Add(new KeyValuePair<Enum, string>(value, GetEnumDescription(value)));
    }

    return list;
}

Now the list.Add() call results in the value and it's string description being displayed in the combobox so I replaced

list.Add(new KeyValuePair<Enum, string>(value, GetEnumDescription(value)));

with

list.Add(GetEnumDescription(value));

and now I'm getting just the descriptive string displayed in the combobox which is what I ultimately want. Now my data binding is broken because it can't find just the string description in the enumeration. I thought this might be related to combobox.DisplayMember and combobox.ValueMember but I haven't been able to resolve the problem yet. Can anyone tell me how the heck I display the descriptive string but have my data binding use the value for storing, etc.? Thank you!!!

like image 830
bmt22033 Avatar asked Aug 03 '11 01:08

bmt22033


1 Answers

Let's go back to your question I answered a few days ago and modify that to suit your new requirements. So I'll keep the colorEnum example in place of your Cities enum in this question.

You're most of the way there - you've got the code to go from the enum to the description string; now you just need to go back the other way.

public static class EnumHelper
{
    // your enum->string method (I just decluttered it a bit :))
    public static string GetEnumDescription(Enum value)
    {
        var fi = value.GetType().GetField(value.ToString());
        var attributes = fi.GetCustomAttributes(typeof(DescriptionAttribute), false);

        if (attributes.Length > 0)
            return ((DescriptionAttribute)attributes[0]).Description;
        else
            return value.ToString();        
    }

    // the method to go from string->enum
    public static T GetEnumFromDescription<T>(string stringValue)
        where T : struct
    {
        foreach (object e in Enum.GetValues(typeof(T)))           
            if (GetEnumDescription((Enum)e).Equals(stringValue))
                return (T)e;
        throw new ArgumentException("No matching enum value found.");
    }

    // and a method to get a list of string values - no KeyValuePair needed
    public static IEnumerable<string> GetEnumDescriptions(Type enumType)
    {
        var strings = new Collection<string>();
        foreach (Enum e in Enum.GetValues(enumType))   
            strings.Add(GetEnumDescription(e));
        return strings;
    }
}

Now, take what you had a few days ago...

public class Person 
{
    [...]
    public colorEnum FavoriteColor { get; set; }
    public string FavoriteColorString
    {
        get { return FavoriteColor.ToString(); }
        set { FavoriteColor = (colorEnum)Enum.Parse(typeof(colorEnum), value);  }
    }
}

and just change it to this:

public class Person 
{
    [...]
    public colorEnum FavoriteColor { get; set; }
    public string FavoriteColorString
    {
        get { return EnumHelper.GetEnumDescription(FavoriteColor); }
        set { FavoriteColor = EnumHelper.GetEnumFromDescription<colorEnum>(value); }
    }
}

As before, you'll bind the combobox SelectedItem value to FavoriteColorString. You don't need to set the DisplayMember or ValueMember properties if you're still using the BindingSource as you were in the other question, which I assume you are.

And change the combobox populating code from:

comboBoxFavoriteColor.DataSource = Enum.GetNames(typeof(colorEnum));

to

comboBoxFavoriteColor.DataSource = EnumHelper.GetEnumDescriptions(typeof(colorEnum));

Now you have the best of all worlds. The user sees the description, your code contains the enum names, and the data store contains the enum values.

like image 189
Igby Largeman Avatar answered Nov 10 '22 00:11

Igby Largeman