1

SLIGHT UPDATE BELOW

I am trying to use the [Description] data annotation attribute with enums in order to display a friendly name. I've searched around a lot and cannot get anything implemented. Right now I have code that will display an enum as a string (using an extension), but I am not liking ThisIsAnEnum as an enum name (which is spaced out by the string extension) and it prohibits me from having longer names (which I need to maintain) such as for a radio button item. My goal is to have longer descriptions for radio button items without having to write really long enums. An extension/helper will probably be the right way to go, but I need to "fit" it into the code I am using, which is where I failed using the many examples out there.

The code I am using is generic, in that depending upon some logic either a radio button list, check box list, drop down list, select list or regular text boxes are displayed. For multi-item lists enum's are used, and the enum name is what is displayed (after using the string extension).

Here is the particular code that displays the enum:

public static IEnumerable<SelectListItem> GetItemsFromEnum<T>
    (T selectedValue = default(T)) where T : struct
    {
        return from name in Enum.GetNames(typeof(T))
               let enumValue = Convert.ToString((T)Enum.Parse(typeof(T), name, true))

               select new SelectListItem
               {
                   Text = name.ProperCase(),
                   Value = enumValue,
                   Selected = enumValue.Equals(selectedValue)
               };
    }

ProperCase is the class that changes the enum to something readable.

I found something that almost worked:

public static string GetEnumDescription<TEnum>(TEnum 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();
    }

in which case I changed code from Text = name.ProperCase(), to Text = name.GetEnumDescription(...) but if I put value in the parenthesis I get a "does not exist in the current context" message (which I tried fixing but just made the problem worse). If I leave it blank I get the "No overload for ... takes 0 arguments" (again, understandable - but I don't know how to fix). And if I put name in the parenthesis the code compiles but upon viewing the page I get the "Object reference not set..." error on this line:

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

I've spent a lot of time on this and know that my stumbling block is the

Text = name.ProperCase(),

code. Any ideas/help? Thanks in advance.

UPDATE:

If I do:

Text = GetEnumDescription(selectedValue),

I actually DO get the [Description] text, however, it just displays for the first enum. So, if I have 5 enums all with different [Description]'s the code just repeats the [Description] for the first enum 5 times instead of displaying differently for each. I hope that makes sense and gets to narrow down the problem.

REMESQ
  • 1,190
  • 2
  • 26
  • 60
  • possible duplicate of [Get the Enum value Description](http://stackoverflow.com/questions/297299/get-the-enumt-value-description) – jrummell Mar 02 '12 at 14:15
  • Not seeing how it's a possible duplicate question. I believe that answers a different problem (or at least I can't get any solution there to work for me), but I defer to your expertise. – REMESQ Mar 02 '12 at 17:02
  • The linked question has the `GetEnumDescription()` part. I didn't see the DropDownList part before. – jrummell Mar 02 '12 at 17:58

1 Answers1

2

I'd recommend you the Display attribute:

public static IEnumerable<SelectListItem> GetItemsFromEnum<T>(T selectedValue = default(T)) where T : struct
{
    return 
        from name in Enum.GetNames(typeof(T))
        let enumValue = Convert.ToString((T)Enum.Parse(typeof(T), name, true))
        select new SelectListItem
        {
            Text = GetEnumDescription(name, typeof(T)),
            Value = enumValue,
            Selected = name == selectedValue.ToString()
        };
}

public static string GetEnumDescription(string value, Type enumType)
{
    var fi = enumType.GetField(value.ToString());
    var display = fi
        .GetCustomAttributes(typeof(DisplayAttribute), false)
        .OfType<DisplayAttribute>()
        .FirstOrDefault();
    if (display != null)
    {
        return display.Name;
    }
    return value;
}

and then you could have:

public enum Foo
{
    [Display(Name = "value 1")]
    Value1,

    Value2,

    [Display(Name = "value 3")]
    Value3
}

And now you could have:

var foo = Foo.Value2;
var values = GetItemsFromEnum(foo);

Also notice that I have modified the Selected clause in the LINQ expression as yours is not correct.

This being said, personally I would recommend you staying away from enums on your view models as they don't play nicely with what's built-in ASP.NET MVC and you will have to reinvent most of the things.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • Thanks for this Darin. It's working to display the attribute for each item, however the `.FirstOrDefault()` line is causing a drop down to bypass the "Select One" text, and in the case of check boxes it's automatically checking the first item (which in my scenario is not preferred). Is there a way around that? Thanks. – REMESQ Mar 02 '12 at 17:43
  • @REMESQ, try a nullable enum if you want a default value for a select box. – Darin Dimitrov Mar 02 '12 at 17:49
  • Sorry for my ignorance: I am already doing, for example `public Foo? FooDropDown { get; set; }` and the only way I know how to null an enum is to do `public Foo? FooDropDown = null;` which obviously won't work together. Might I trouble you for an example with the code you posted? Thanks. – REMESQ Mar 02 '12 at 18:30
  • Resolved: I kept the original `Selected` and your solution worked and the check boxes are unchecked and the drop down has the default value of "Select One". Thanks! – REMESQ Mar 02 '12 at 18:55