ChatGPT解决这个技术问题 Extra ChatGPT

How do I have an enum bound combobox with custom string formatting for enum values?

In the post Enum ToString, a method is described to use the custom attribute DescriptionAttribute like this:

Enum HowNice {
  [Description("Really Nice")]
  ReallyNice,
  [Description("Kinda Nice")]
  SortOfNice,
  [Description("Not Nice At All")]
  NotNice
}

And then, you call a function GetDescription, using syntax like:

GetDescription<HowNice>(NotNice); // Returns "Not Nice At All"

But that doesn't really help me when I want to simply populate a ComboBox with the values of an enum, since I cannot force the ComboBox to call GetDescription.

What I want has the following requirements:

Reading (HowNice)myComboBox.selectedItem will return the selected value as the enum value.

The user should see the user-friendly display strings, and not just the name of the enumeration values. So instead of seeing "NotNice", the user would see "Not Nice At All".

Hopefully, the solution will require minimal code changes to existing enumerations.

Obviously, I could implement a new class for each enum that I create, and override its ToString(), but that's a lot of work for each enum, and I'd rather avoid that.

Any ideas?

Heck, I'll even throw in a hug as a bounty :-)

jjnguy is correct that Java enums solve this nicely (javahowto.blogspot.com/2006/10/…), but that's of questionable relevance.
Java Enums are a joke. Maybe they'll add Properties in 2020 :/
For a lighter (but arguably less-robust) solution see my thread.

A
Anton Gogolev

ComboBox has everything you need: the FormattingEnabled property, which you should set to true, and Format event, where you'll need to place desired formatting logic. Thus,

myComboBox.FormattingEnabled = true;
myComboBox.Format += delegate(object sender, ListControlConvertEventArgs e)
    {
        e.Value = GetDescription<HowNice>((HowNice)e.Value);
    }

Does this only work with databound comboboxes? I can't get the Format event to fire otherwise.
the only problem here is that you cant have the list sorted with your logic
This is a great solution. I would need it to work with a DataGridComboBoxColumn though. Any chance to solve it? I'm not able to find a way to get access to the ComboBox of the DataGridComboBoxColumn.
S
Sander

Don't! Enums are primitives and not UI objects - making them serve the UI in .ToString() would be quite bad from a design standpoint. You are trying to solve the wrong problem here: the real issue is that you do not want Enum.ToString() to show up in the combo box!

Now this is a very solveable problem indeed! You create a UI object to represent your combo box items:

sealed class NicenessComboBoxItem
{
    public string Description { get { return ...; } }
    public HowNice Value { get; private set; }

    public NicenessComboBoxItem(HowNice howNice) { Value = howNice; }
}

And then just add instances of this class to your combo box's Items collection and set these properties:

comboBox.ValueMember = "Value";
comboBox.DisplayMember = "Description";

I agree wholeheartedly. Neither should you expose the result of ToString() to the UI. And, you don't get localization.
I know this is old, but how is that any different?
I've seen a similar solution where instead of using a custom class, they mapped the enum values to a Dictionary and used the Key and Value properties as the DisplayMember and ValueMember.
m
m.edmondson

You could write an TypeConverter that reads specified attributes to look them up in your resources. Thus you would get multi-language support for display names without much hassle.

Look into the TypeConverter's ConvertFrom/ConvertTo methods, and use reflection to read attributes on your enum fields.


OK, I wrote some code (see my answer to this question) - do you think that's enough, am I missing something?
Nice one. Better overal, but might be overkill for your run-of-the-mill never-will-be-globalized-in-any-way piece of software. (I know, that assumption will turn out to be false later. ;-))
C
Community

TypeConverter. I think this is what I was looking for. All hail Simon Svensson!

[TypeConverter(typeof(EnumToStringUsingDescription))]
Enum HowNice {
  [Description("Really Nice")]
  ReallyNice,
  [Description("Kinda Nice")]
  SortOfNice,
  [Description("Not Nice At All")]
  NotNice
}

All I need to change in my current enum is add this line before their declaration.

[TypeConverter(typeof(EnumToStringUsingDescription))]

Once I do that, any enum will get displayed using the DescriptionAttribute of its fields.

Oh, and the TypeConverter would be defined like this:

public class EnumToStringUsingDescription : TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return (sourceType.Equals(typeof(Enum)));
    }

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
        return (destinationType.Equals(typeof(String)));
    }

    public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
    {
        return base.ConvertFrom(context, culture, value);
    }

    public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
    {
        if (!destinationType.Equals(typeof(String)))
        {
            throw new ArgumentException("Can only convert to string.", "destinationType");
        }

        if (!value.GetType().BaseType.Equals(typeof(Enum)))
        {
            throw new ArgumentException("Can only convert an instance of enum.", "value");
        }

        string name = value.ToString();
        object[] attrs = 
            value.GetType().GetField(name).GetCustomAttributes(typeof(DescriptionAttribute), false);
        return (attrs.Length > 0) ? ((DescriptionAttribute)attrs[0]).Description : name;
    }
}

This helps me with my ComboBox case, but obviously doesn't actually override the ToString(). I guess I'll settle for this meanwhile...


You're handling Enum -> String, but you will also need Enum > InstanceDescriptor, and String -> Enum if you want a complete implementation. But I guess displaying it is enough for your needs at the moment. ;)
This solution only works when your descriptions are static, unfortunately.
By the way, the use of TypeConverter is not bound to static descritions, coverter can populate values from other sources than attributes.
Been pulling my hair for a few hours now, but it still doesn't seem to work even in simple console apps. I decorated the enum with [TypeConverter(typeof(EnumToStringUsingDescription))] public enum MyEnum {[Description("Blah")] One}, tried doing Console.WriteLine(MyEnum.One) and it still comes out as "One". Do you need some special magic like TypeDescriptor.GetConverter(typeof(MyEnum)).ConvertToString(MyEnum.One) (which does work fine)?
@scraimer I have posted a version of your code supporting flags. all rights reserved to you...
T
Tyler Durden

Using your enumeration example:

using System.ComponentModel;

Enum HowNice
{
    [Description("Really Nice")]
    ReallyNice,
    [Description("Kinda Nice")]
    SortOfNice,
    [Description("Not Nice At All")]
    NotNice
}

Create an Extension:

public static class EnumExtensions
{
    public static string Description(this Enum value)
    {
        var enumType = value.GetType();
        var field = enumType.GetField(value.ToString());
        var attributes = field.GetCustomAttributes(typeof(DescriptionAttribute),
                                                   false);
        return attributes.Length == 0
            ? value.ToString()
            : ((DescriptionAttribute)attributes[0]).Description;
    }
}

Then you can use something like the following:

HowNice myEnum = HowNice.ReallyNice;
string myDesc = myEnum.Description();

See: http://www.blackwasp.co.uk/EnumDescription.aspx for more information. Credit goes to Richrd Carr for the solution


I followed the details at the referred site and used it as follows, looks straightforward for me 'string myDesc = HowNice.ReallyNice.Description();' myDesc will output Really Nice
G
Guffa

You could make a generic struct that you could use for all of your enums that has descriptions. With implicit conversions to and from the class, your variables still works like the enum except for the ToString method:

public struct Described<T> where T : struct {

    private T _value;

    public Described(T value) {
        _value = value;
    }

    public override string ToString() {
        string text = _value.ToString();
        object[] attr =
            typeof(T).GetField(text)
            .GetCustomAttributes(typeof(DescriptionAttribute), false);
        if (attr.Length == 1) {
            text = ((DescriptionAttribute)attr[0]).Description;
        }
        return text;
    }

    public static implicit operator Described<T>(T value) {
        return new Described<T>(value);
    }

    public static implicit operator T(Described<T> value) {
        return value._value;
    }

}

Usage example:

Described<HowNice> nice = HowNice.ReallyNice;

Console.WriteLine(nice == HowNice.ReallyNice); // writes "True"
Console.WriteLine(nice); // writes "Really Nice"

M
Marc Gravell

I don't think you can do it without simply binding to a different type - at least, not conveniently. Normally, even if you can't control ToString(), you can use a TypeConverter to do custom formatting - but IIRC the System.ComponentModel stuff doesn't respect this for enums.

You could bind to a string[] of the descriptions, or a something essentially like a key/value pair? (desription/value) - something like:

class EnumWrapper<T> where T : struct
{
    private readonly T value;
    public T Value { get { return value; } }
    public EnumWrapper(T value) { this.value = value; }
    public string Description { get { return GetDescription<T>(value); } }
    public override string ToString() { return Description; }

    public static EnumWrapper<T>[] GetValues()
    {
        T[] vals = (T[])Enum.GetValues(typeof(T));
        return Array.ConvertAll(vals, v => new EnumWrapper<T>(v));
    }
}

And then bind to EnumWrapper<HowNice>.GetValues()


The name 'GetDescription' does not exist in current context. i m using .NET 4.0
@MuhammadAdeelZahid look closely at the start of the question - that comes from the linked post: stackoverflow.com/questions/479410/enum-tostring
sorry but can't get any clue from the question. your method is not compiling and shows the error.
Hi Marc, I tried your idea. It's working, but the theComboBox.SelectItem is type of EnumWrapper<T>, instead of T itself. I think scraimer wants Reading (HowNice)myComboBox.selectedItem will return the selected value as the enum value..
d
deutschZuid

The best way to do this is to make a class.

class EnumWithToString {
    private string description;
    internal EnumWithToString(string desc){
        description = desc;
    }
    public override string ToString(){
        return description;
    }
}

class HowNice : EnumWithToString {

    private HowNice(string desc) : base(desc){}

    public static readonly HowNice ReallyNice = new HowNice("Really Nice");
    public static readonly HowNice KindaNice = new HowNice("Kinda Nice");
    public static readonly HowNice NotVeryNice = new HowNice("Really Mean!");
}

I believe that is the best way to do it.

When stuffed in comboboxes the pretty ToString will be shown, and the fact that no one can make any more instances of your class essentially makes it an enum.

p.s. there may need to be some slight syntax fixes, I'm not super good with C#. (Java guy)


How does this help with the combobox problem?
Well, now, when the new object is put in a combobox, its ToString will be properly displayed, and the class still acts like an enum.
Would have been my answer as well.
And seeing how the original poster explicitly did not want a class. I dont't think a class is that much more work. You can abstract the description and ToString override away to a parent class for all enums. After this all you need is a constructor private HowNice(String desc) : base(desc) { } and the static fields.
I was hoping to avoid this, since it means that each and every enumeration I make will require its own class. Ugh.
B
Björn

Not possible to override the ToString() of enums in C#. However, you can use extension methods;

public static string ToString(this HowNice self, int neverUsed)
{
    switch (self)
    {
        case HowNice.ReallyNice:
            return "Rilly, rilly nice";
            break;
    ...

Of course you will have to make an explicit call to the method, i.e;

HowNice.ReallyNice.ToString(0)

This is not a nice solution, with a switch statement and all - but it should work and hopefully whitout to many rewrites...


Be aware that the control that binds to your enum would not call this extension method, it would call the default implementation.
Right. So this is a viable option if you need a description somewhere, it does not help with the posed combobox problem.
A bigger problem is that this will never get called (as an extension method) - instance methods that already exist always take priority.
Of course Marc is right (as always?). My .NET experience is minimal, but providing a dummy parameter to the method should do the trick. Edited answer.
and to populate combo-box items once we've this extension method we can write : foreach (HowNice item in (HowNice[])Enum.GetValues(typeof(HowNice))) { myComboBox.Items.Add(item.ToString(0)); }
R
Richard Szalay

Given that you'd rather not create a class for each enum, I'd recommend creating a dictionary of the enum value/display text and binding that instead.

Note that this has a dependency on the GetDescription method methods in the original post.

public static IDictionary<T, string> GetDescriptions<T>()
    where T : struct
{
    IDictionary<T, string> values = new Dictionary<T, string>();

    Type type = enumerationValue.GetType();
    if (!type.IsEnum)
    {
        throw new ArgumentException("T must be of Enum type", "enumerationValue");
    }

    //Tries to find a DescriptionAttribute for a potential friendly name
    //for the enum
    foreach (T value in Enum.GetValues(typeof(T)))
    {
        string text = value.GetDescription();

        values.Add(value, text);
    }

    return values;
}

Nice idea. But how would I use this with a combobox? Once the user selects an items from the combobox, how do I know which of the items he selected? Search by the Description string? That makes my skin itch... (there might be a string "collision" between Description strings)
The selected item's Key will be the actual enum value. Also, don't collide the description strings - how will the user tell the difference?
if you have description strings that collide, then you shouldn't be binding the values of the enum to a combobox directly anyway.
hmmm... Well, could you give me example code on how you would add items to the combobox? All I can think of is "foreach (string s in descriptionsDict.Values) { this.combobox.Items.Add(s); }"
ComboBox.DataSource = dictionary;
A
Avi Turner

Following up on @scraimer answer, here is a version of the enum-to-string type converter, which supports flags as well:

    /// <summary>
/// A drop-in converter that returns the strings from 
/// <see cref="System.ComponentModel.DescriptionAttribute"/>
/// of items in an enumaration when they are converted to a string,
/// like in ToString().
/// </summary>
public class EnumToStringUsingDescription : TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return (sourceType.Equals(typeof(Enum)));
    }

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
        return (destinationType.Equals(typeof(String)));
    }

    public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
    {
        return base.ConvertFrom(context, culture, value);
    }

    public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
    {
        if (destinationType.Equals(typeof(String)))
        {
            string name = value.ToString();
            Type effectiveType = value.GetType();          

            if (name != null)
            {
                FieldInfo fi = effectiveType.GetField(name);
                if (fi != null)
                {
                    object[] attrs =
                    fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
                    return (attrs.Length > 0) ? ((DescriptionAttribute)attrs[0]).Description : name;
                }

            }
        }

        return base.ConvertTo(context, culture, value, destinationType);
    }

    /// <summary>
    /// Coverts an Enums to string by it's description. falls back to ToString.
    /// </summary>
    /// <param name="value">The value.</param>
    /// <returns></returns>
    public string EnumToString(Enum value)
    {
        //getting the actual values
        List<Enum> values = EnumToStringUsingDescription.GetFlaggedValues(value);
        //values.ToString();
        //Will hold results for each value
        List<string> results = new List<string>();
        //getting the representing strings
        foreach (Enum currValue in values)
        {
            string currresult = this.ConvertTo(null, null, currValue, typeof(String)).ToString();;
            results.Add(currresult);
        }

        return String.Join("\n",results);

    }

    /// <summary>
    /// All of the values of enumeration that are represented by specified value.
    /// If it is not a flag, the value will be the only value retured
    /// </summary>
    /// <param name="value">The value.</param>
    /// <returns></returns>
    private static List<Enum> GetFlaggedValues(Enum value)
    {
        //checking if this string is a flaged Enum
        Type enumType = value.GetType();
        object[] attributes = enumType.GetCustomAttributes(true);
        bool hasFlags = false;
        foreach (object currAttibute in attributes)
        {
            if (enumType.GetCustomAttributes(true)[0] is System.FlagsAttribute)
            {
                hasFlags = true;
                break;
            }
        }
        //If it is a flag, add all fllaged values
        List<Enum> values = new List<Enum>();
        if (hasFlags)
        {
            Array allValues = Enum.GetValues(enumType);
            foreach (Enum currValue in allValues)
            {
                if (value.HasFlag(currValue))
                {
                    values.Add(currValue);
                }
            }



        }
        else//if not just add current value
        {
            values.Add(value);
        }
        return values;
    }

}

And an extension method for using it:

    /// <summary>
    /// Converts an Enum to string by it's description. falls back to ToString
    /// </summary>
    /// <param name="enumVal">The enum val.</param>
    /// <returns></returns>
    public static string ToStringByDescription(this Enum enumVal)
    {
        EnumToStringUsingDescription inter = new EnumToStringUsingDescription();
        string str = inter.EnumToString(enumVal);
        return str;
    }

D
Dan C.

I would write a generic class for use with any type. I've used something like this in the past:

public class ComboBoxItem<T>
{
    /// The text to display.
    private string text = "";
    /// The associated tag.
    private T tag = default(T);

    public string Text
    {
        get
        {
            return text;
        }
    }

    public T Tag
    {
        get
        {
            return tag;
        }
    }

    public override string ToString()
    {
        return text;
    }

    // Add various constructors here to fit your needs
}

On top of this, you could add a static "factory method" to create a list of combobox items given an enum type (pretty much the same as the GetDescriptions method you have there). This would save you of having to implement one entity per each enum type, and also provide a nice/logical place for the "GetDescriptions" helper method (personally I would call it FromEnum(T obj) ...


p
peSHIr

Create a collection that contains what you need (like simple objects containing a Value property containing the HowNice enum value and a Description property containing GetDescription<HowNice>(Value) and databind the combo to that collection.

Bit like this:

Combo.DataSource = new EnumeratedValueCollection<HowNice>();
Combo.ValueMember = "Value";
Combo.DisplayMember = "Description";

when you have a collection class like this:

using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace Whatever.Tickles.Your.Fancy
{
    public class EnumeratedValueCollection<T> : ReadOnlyCollection<EnumeratedValue<T>>
    {
        public EnumeratedValueCollection()
            : base(ListConstructor()) { }
        public EnumeratedValueCollection(Func<T, bool> selection)
            : base(ListConstructor(selection)) { }
        public EnumeratedValueCollection(Func<T, string> format)
            : base(ListConstructor(format)) { }
        public EnumeratedValueCollection(Func<T, bool> selection, Func<T, string> format)
            : base(ListConstructor(selection, format)) { }
        internal EnumeratedValueCollection(IList<EnumeratedValue<T>> data)
            : base(data) { }

        internal static List<EnumeratedValue<T>> ListConstructor()
        {
            return ListConstructor(null, null);
        }

        internal static List<EnumeratedValue<T>> ListConstructor(Func<T, string> format)
        {
            return ListConstructor(null, format);
        }

        internal static List<EnumeratedValue<T>> ListConstructor(Func<T, bool> selection)
        {
            return ListConstructor(selection, null);
        }

        internal static List<EnumeratedValue<T>> ListConstructor(Func<T, bool> selection, Func<T, string> format)
        {
            if (null == selection) selection = (x => true);
            if (null == format) format = (x => GetDescription<T>(x));
            var result = new List<EnumeratedValue<T>>();
            foreach (T value in System.Enum.GetValues(typeof(T)))
            {
                if (selection(value))
                {
                    string description = format(value);
                    result.Add(new EnumeratedValue<T>(value, description));
                }
            }
            return result;
        }

        public bool Contains(T value)
        {
            return (Items.FirstOrDefault(item => item.Value.Equals(value)) != null);
        }

        public EnumeratedValue<T> this[T value]
        {
            get
            {
                return Items.First(item => item.Value.Equals(value));
            }
        }

        public string Describe(T value)
        {
            return this[value].Description;
        }
    }

    [System.Diagnostics.DebuggerDisplay("{Value} ({Description})")]
    public class EnumeratedValue<T>
    {
        private T value;
        private string description;
        internal EnumeratedValue(T value, string description) {
            this.value = value;
            this.description = description;
        }
        public T Value { get { return this.value; } }
        public string Description { get { return this.description; } }
    }

}

As you can see, this collection is easily customizable with lambda's to select a subset of your enumerator and/or implement a custom formatting to string instead of using the GetDescription<T>(x) function you mention.


Excellent, but I'm looking for something that requires even less work in the code.
Even if you can use the same generic collection for this kind of thing for all your enumerators? I wasn't suggesting custom writing such a collection for each enum, of course.
m
majkinetor

You could use PostSharp to target Enum.ToString and add aditionall code you want. This doesn't require any code changes.


佚名

What you need is to turn an enum into a ReadonlyCollection and bind the collection to the combobox (or any Key-Value Pair enabled control for that matter)

First off you need a class to contain the items of the list. Since all you need is the int/string pair I suggest using an interface and a base class combo so that you can implement the functionality in any object you want:

public interface IValueDescritionItem
{
    int Value { get; set;}
    string Description { get; set;}
}

public class MyItem : IValueDescritionItem
{
    HowNice _howNice;
    string _description;

    public MyItem()
    {

    }

    public MyItem(HowNice howNice, string howNice_descr)
    {
        _howNice = howNice;
        _description = howNice_descr;
    }

    public HowNice Niceness { get { return _howNice; } }
    public String NicenessDescription { get { return _description; } }


    #region IValueDescritionItem Members

    int IValueDescritionItem.Value
    {
        get { return (int)_howNice; }
        set { _howNice = (HowNice)value; }
    }

    string IValueDescritionItem.Description
    {
        get { return _description; }
        set { _description = value; }
    }

    #endregion
}

Here is the interface and a sample class that implements it.Notice that the class' Key is strongly typed to the Enum, and that the IValueDescritionItem proprties are implemented explicitely (so the class can have whatever properties and you can CHOOSE the ones that implement the Key/Value pair.

Now the EnumToReadOnlyCollection class:

public class EnumToReadOnlyCollection<T,TEnum> : ReadOnlyCollection<T> where T: IValueDescritionItem,new() where TEnum : struct
{
    Type _type;

    public EnumToReadOnlyCollection() : base(new List<T>())
    {
        _type = typeof(TEnum);
        if (_type.IsEnum)
        {
            FieldInfo[] fields = _type.GetFields();

            foreach (FieldInfo enum_item in fields)
            {
                if (!enum_item.IsSpecialName)
                {
                    T item = new T();
                    item.Value = (int)enum_item.GetValue(null);
                    item.Description = ((ItemDescription)enum_item.GetCustomAttributes(false)[0]).Description;
                    //above line should be replaced with proper code that gets the description attribute
                    Items.Add(item);
                }
            }
        }
        else
            throw new Exception("Only enum types are supported.");
    }

    public T this[TEnum key]
    {
        get 
        {
            return Items[Convert.ToInt32(key)];
        }
    }

}

So all you need in your code is :

private EnumToReadOnlyCollection<MyItem, HowNice> enumcol;
enumcol = new EnumToReadOnlyCollection<MyItem, HowNice>();
comboBox1.ValueMember = "Niceness";
comboBox1.DisplayMember = "NicenessDescription";
comboBox1.DataSource = enumcol;

Remember that your collection is typed with MyItem so the combobox value should return an enum value if you bind to the appropriate proprtie.

I added the T this[Enum t] property to make the collection even more usefull than a simple combo consumable, for example textBox1.Text = enumcol[HowNice.ReallyNice].NicenessDescription;

You can of course chose to turn MyItem into a Key/Value class used only for this puprose effectively skipping MyItem in the type arguments of EnumToReadnlyCollection altogether, but then you'd be forced to go with int for the key (meaning getting combobox1.SelectedValue would return int and not the enum type). You work around that if you create a KeyValueItem class to replace MyItem and so on and so forth...


T
Tim Cooper

Sorry for getting this old thread up.

I would go the following way to localize enum, as it can display meaningful and localized values to user, not just description, through a dropdownlist text field in this example.

First, I create a simple method called OwToStringByCulture to get localized strings from a global resources file, in this example it is BiBongNet.resx in the App_GlobalResources folder. Inside this resource file, make sure you have all strings the same as the values of the enum (ReallyNice, SortOfNice, NotNice). In this method, I pass in the parameter: resourceClassName which is usually the name of the resource file.

Next, I create a static method to fill a dropdownlist with enum as its datasource, called OwFillDataWithEnum. This method can be used with any enum later.

Then in the page with a dropdownlist called DropDownList1, I set in the Page_Load the following just one simple line of code to fill the enum to the dropdownlist.

 BiBongNet.OwFillDataWithEnum<HowNice>(DropDownList1, "BiBongNet");

That's it. I think with some simple methods like these, you can fill any list control with any enum, with not just as descriptive values but localized text to display. You can make all these methods as extension methods for better use.

Hope this help. Share to get shared!

Here are the methods:

public class BiBongNet
{

        enum HowNice
        {
            ReallyNice,
            SortOfNice,
            NotNice
        }

        /// <summary>
        /// This method is for filling a listcontrol,
        /// such as dropdownlist, listbox... 
        /// with an enum as the datasource.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ctrl"></param>
        /// <param name="resourceClassName"></param>
        public static void OwFillDataWithEnum<T>(ListControl ctrl, string resourceClassName)
        {
            var owType = typeof(T);
            var values = Enum.GetValues(owType);
            for (var i = 0; i < values.Length; i++)
            {
                //Localize this for displaying listcontrol's text field.
                var text = OwToStringByCulture(resourceClassName, Enum.Parse(owType, values.GetValue(i).ToString()).ToString());
                //This is for listcontrol's value field
                var key = (Enum.Parse(owType, values.GetValue(i).ToString()));
                //add values of enum to listcontrol.
                ctrl.Items.Add(new ListItem(text, key.ToString()));
            }
        }

        /// <summary>
        /// Get localized strings.
        /// </summary>
        /// <param name="resourceClassName"></param>
        /// <param name="resourceKey"></param>
        /// <returns></returns>
        public static string OwToStringByCulture(string resourceClassName, string resourceKey)
        {
                return (string)HttpContext.GetGlobalResourceObject(resourceClassName, resourceKey);
        }
}

S
Sérgio
Enum HowNice {
  [Description("Really Nice")]
  ReallyNice,
  [Description("Kinda Nice")]
  SortOfNice,
  [Description("Not Nice At All")]
  NotNice
}

To resolve this you should use an extension Method and an Array of Strings like so:

Enum HowNice {
  ReallyNice  = 0,
  SortOfNice  = 1,
  NotNice     = 2
}

internal static class HowNiceIsThis
{
 const String[] strings = { "Really Nice", "Kinda Nice", "Not Nice At All" }

 public static String DecodeToString(this HowNice howNice)
 {
   return strings[(int)howNice];
 }
}

Simple code and fast decoding.


the strings variable should be Static and declared like so: Static String[] strings = new [] {...}
The only problem with this, is that you will need to have a function for every enumeration, and the description will be apart of the enumeration itself...
U
Unheilig

I tried this approach and it worked for me.

I created a wrapper class for enums and overloaded the implicit operator so that I can assign it to enum variables (in my case I had to bind an object to a ComboBox value).

You can use reflection to format the enum values the way you want to, in my case I retrieve the DisplayAttribute out of the enum values (if existent).

Hope this helps.

public sealed class EnumItem<T>
{
    T value;

    public override string ToString()
    {
        return Display;
    }

    public string Display { get; private set; }
    public T Value { get; set; }

    public EnumItem(T val)
    {
        value = val;
        Type en = val.GetType();
        MemberInfo res = en.GetMember(val.ToString())?.FirstOrDefault();
        DisplayAttribute display = res.GetCustomAttribute<DisplayAttribute>();
        Display = display != null ? String.Format(display.Name, val) : val.ToString();
    }

    public static implicit operator T(EnumItem<T> val)
    {
        return val.Value;
    }

    public static implicit operator EnumItem<T>(T val)
    {
        return new EnumItem<T>(val);
    }
}

EDIT:

Just in case, I use the following function to get the enum values that I use for the DataSource of the ComboBox

public static class Utils
{
    public static IEnumerable<EnumItem<T>> GetEnumValues<T>()
    {
        List<EnumItem<T>> result = new List<EnumItem<T>>();
        foreach (T item in Enum.GetValues(typeof(T)))
        {
            result.Add(item);
        }
        return result;
    }
}

a
awe

Once you have the GetDescription method (it needs to be global static), you could use this through an extension method:

public static string ToString(this HowNice self)
{
    return GetDescription<HowNice>(self);
}

J
Jason Sturges
Enum HowNice {   
[StringValue("Really Nice")]   
ReallyNice,   
[StringValue("Kinda Nice")]   
SortOfNice,   
[StringValue("Not Nice At All")]   
NotNice 
}

Status = ReallyNice.GetDescription()

Welcome to stackoverflow! It's always better to provide a short description for a sample code to improve the post accuracy :)
a
awe

You can define Enum as

Enum HowNice {   
[StringValue("Really Nice")]   
ReallyNice,   
[StringValue("Kinda Nice")]   
SortOfNice,   
[StringValue("Not Nice At All")]   
NotNice 
} 

and then use HowNice.GetStringValue().


This does not compile (I have .NET 3.5). Where is ´StringValue´ declared?
The answer from @scraimer is the same, except that he is using an attribute out of the framework, whereas you use some kind of self defined attribute.