Как мне связать связанный с enum combobox с настраиваемым форматированием строк для значений перечисления?

В сообщении Enum ToString описан способ использования пользовательского атрибута DescriptionAttribute следующим образом:

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

И затем вы вызываете функцию GetDescription, используя синтаксис вроде:

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

Но это действительно не помогает мне , когда я хочу просто заполнить ComboBox значениями enum, поскольку я не могу заставить ComboBox вызывать GetDescription.

Я хочу иметь следующие требования:

  • Чтение (HowNice)myComboBox.selectedItem вернет выбранное значение в качестве значения перечисления.
  • Пользователь должен увидеть удобные для пользователя строки отображения, а не только имя значений перечисления. Поэтому вместо того, чтобы видеть "NotNice", пользователь увидит "Not Nice At All".
  • Надеемся, что решение потребует минимальных изменений кода для существующих перечислений.

Очевидно, я мог бы реализовать новый класс для каждого перечисления, который я создаю, и переопределить его ToString(), но это много работы для каждого перечисления, и я бы предпочел избежать этого.

Любые идеи?

Черт, я даже закрою объятие в качестве награды: -)

Ответ 1

Вы можете написать TypeConverter, который считывает указанные атрибуты, чтобы просмотреть их в ваших ресурсах. Таким образом, вы получите многоязычную поддержку для отображения имен без особых хлопот.

Посмотрите на методы конвертации TypeConverter ConvertFrom/ConvertTo и используйте отражение для чтения атрибутов в своих полях перечисления.

Ответ 2

ComboBox есть все, что вам нужно: свойство FormattingEnabled, которое вы должны установить в true и Format событие, где вам нужно будет поместить нужную логику форматирования. Таким образом,

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

Ответ 3

Не надо! Перечисления - это примитивы, а не объекты пользовательского интерфейса, что делает их доступными для пользовательского интерфейса в .ToString() с точки зрения дизайна. Вы пытаетесь решить неправильную проблему здесь: реальная проблема заключается в том, что вы не хотите, чтобы Enum.ToString() отображался в поле со списком!

Теперь это очень решаемая проблема! Вы создаете объект пользовательского интерфейса для представления ваших элементов со списком:

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

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

А затем просто добавьте экземпляры этого класса в свой сборник "Коллекция предметов" и установите следующие свойства:

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

Ответ 4

TypeConverter. Я думаю, что это то, что я искал. Все приветствуют Саймон Свенссон!

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

Все, что мне нужно изменить в моем текущем перечислении, добавляет эту строку перед объявлением.

[TypeConverter(typeof(EnumToStringUsingDescription))]

Как только я это сделаю, любое перечисление будет отображаться с помощью DescriptionAttribute его полей.

О, а TypeConverter будет определяться следующим образом:

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;
    }
}

Это помогает мне в моем случае ComboBox, но, очевидно, на самом деле не отменяет ToString(). Думаю, я соглашусь на это тем временем...

Ответ 5

Используя пример перечисления:

using System.ComponentModel;

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

Создать расширение:

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;
    }
}

Затем вы можете использовать что-то вроде следующего:

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

Для получения дополнительной информации см. http://www.blackwasp.co.uk/EnumDescription.aspx. Кредит отправляется Richrd Carr для решения

Ответ 6

Вы можете создать общую структуру, которую вы могли бы использовать для всех ваших перечислений с описаниями. При неявных преобразованиях в класс и из него ваши переменные по-прежнему работают как перечисление, за исключением метода ToString:

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;
    }

}

Пример использования:

Described<HowNice> nice = HowNice.ReallyNice;

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

Ответ 7

Лучший способ сделать это - создать класс.

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!");
}

Я считаю, что это лучший способ сделать это.

При добавлении в comboboxes будет отображаться симпатичная ToString, и тот факт, что никто не может делать больше экземпляров вашего класса, по сути делает его перечислением.

p.s. возможно, должны быть некоторые небольшие синтаксические исправления, я не очень хорошо разбираюсь в С#. (Java-парень)

Ответ 8

Я не думаю, что вы можете сделать это без привязки к другому типу - по крайней мере, не удобно. Как правило, даже если вы не можете управлять ToString(), вы можете использовать TypeConverter для пользовательского форматирования, но материал IIRC System.ComponentModel не учитывает это для перечислений.

Вы можете привязать к string[] описаниям или что-то по существу как пара ключ/значение? (desription/value) - что-то вроде:

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));
    }
}

И затем привязитесь к EnumWrapper<HowNice>.GetValues()

Ответ 9

Невозможно переопределить ToString() перечислений в С#. Однако вы можете использовать методы расширения;

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

Конечно, вам нужно будет сделать явный вызов метода, т.е.

HowNice.ReallyNice.ToString(0)

Это нехорошее решение, с оператором switch и всем - но оно должно работать и, надеюсь, без изменений для многих переписываемых...

Ответ 10

Учитывая, что вы предпочитаете не создавать класс для каждого перечисления, я бы рекомендовал вместо этого создать словарь значения/отображаемого текста перечисления и привязки.

Обратите внимание, что это имеет зависимость от методов метода GetDescription в исходном сообщении.

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;
}

Ответ 11

В ответ на ответ @scraimer, вот версия конвертера типа перечисления в строку, которая также поддерживает флаги:

    /// <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 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;
    }

}

И метод расширения для его использования:

    /// <summary>
    /// Converts an Enum to string by it 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;
    }

Ответ 12

Создайте коллекцию, в которой содержится то, что вам нужно (например, простые объекты, содержащие свойство Value, содержащее значение enum HowNice и свойство Description, содержащее GetDescription<HowNice>(Value) и привязку данных к этой коллекции.

Бит выглядит следующим образом:

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

когда у вас есть такой класс коллекции:

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; } }
    }

}

Как вы можете видеть, эта коллекция легко настраивается с помощью лямбда, чтобы выбрать подмножество вашего перечислителя и/или реализовать настраиваемое форматирование до string вместо использования функции GetDescription<T>(x), которую вы упоминаете.

Ответ 13

Я бы написал общий класс для использования с любым типом. Я использовал что-то вроде этого в прошлом:

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
}

Кроме того, вы можете добавить статический метод "factory", чтобы создать список элементов combobox с учетом типа перечисления (в значительной степени аналогично методу GetDescriptions, который у вас есть). Это избавит вас от необходимости реализовать один объект для каждого типа перечисления, а также обеспечить хорошее/логическое место для вспомогательного метода GetDescriptions (лично я бы назвал его FromEnum (T obj)...

Ответ 14

Вы можете использовать PostSharp для таргетинга Enum.ToString и добавить дополнительный код, который вы хотите. Это не требует каких-либо изменений кода.

Ответ 15

Вам нужно преобразовать enum в ReadonlyCollection и привязать коллекцию к combobox (или любому элементу управления, поддерживающему значение Key-Value Pair).

Сначала вам нужен класс, чтобы содержать элементы списка. Поскольку все, что вам нужно, это пара int/string, я предлагаю использовать интерфейс и комбо базового класса, чтобы вы могли реализовать функциональность любого объекта, который вы хотите:

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
}

Вот интерфейс и класс класса, который его реализует. Обратите внимание, что класс "Key" строго типизирован для Enum и что свойства IValueDescritionItem реализованы явно (так что класс может иметь любые свойства, и вы можете ВЫБРАТЬ те из них которые реализуют пару Key/Value.

Теперь класс EnumToReadOnlyCollection:

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)];
        }
    }

}

Итак, все, что вам нужно в вашем коде:

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

Помните, что ваша коллекция напечатана с помощью MyItem, поэтому значение combobox должно возвращать значение перечисления, если вы привязываетесь к соответствующему proprtie.

Я добавил свойство T этого [Enum t], чтобы сделать коллекцию еще более полезной, чем простое комбо, например textBox1.Text = enumcol [HowNice.ReallyNice].NicenessDescription;

Вы можете, конечно, выбрать MyItem в класс Key/Value, используемый только для этого puprose, который эффективно пропускает MyItem в аргументах типа EnumToReadnlyCollection в целом, но тогда вы будете вынуждены пойти с int для ключа (что означает получение combobox1.SelectedValue вернет int, а не тип перечисления). Вы обходите это, если вы создаете класс KeyValueItem для замены MyItem и т.д. И т.д....

Ответ 16

Извините за то, что вы добавили эту старую нить.

Я бы сделал следующий путь для локализации перечисления, так как он может отображать значимые и локализованные значения для пользователя, а не просто для описания, через текстовое поле выпадающего списка в этом примере.

Сначала я создаю простой метод под названием OwToStringByCulture для получения локализованных строк из файла глобальных ресурсов, в этом примере это BiBongNet.resx в папке App_GlobalResources. Внутри этого файла ресурсов убедитесь, что все строки совпадают с значениями перечисления (ReallyNice, SortOfNice, NotNice). В этом методе я передаю параметр: resourceClassName, который обычно является именем файла ресурсов.

Затем я создаю статический метод, чтобы заполнить выпадающий список с перечислением как его источником данных, называемым OwFillDataWithEnum. Этот метод можно использовать с любым перечислением позже.

Затем на странице с выпадающим списком, названным DropDownList1, я установил в Page_Load следующую только одну простую строку кода, чтобы заполнить перечисление в раскрывающемся списке.

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

Что это. Я думаю, что с помощью некоторых простых методов, таких как эти, вы можете заполнить любой элемент управления списком любым перечислением, причем не только как описательные значения, но и локализованный текст для отображения. Вы можете использовать все эти методы в качестве методов расширения для лучшего использования.

Надеюсь на эту помощь. Поделиться, чтобы получить общий доступ!

Вот методы:

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 text field.
                var text = OwToStringByCulture(resourceClassName, Enum.Parse(owType, values.GetValue(i).ToString()).ToString());
                //This is for listcontrol 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);
        }
}

Ответ 17

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

Чтобы решить эту проблему, вы должны использовать метод расширения и массив строк как:

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];
 }
}

Простой код и быстрое декодирование.

Ответ 18

Я пробовал этот подход, и это сработало для меня.

Я создал класс оболочки для перечислений и перегрузил неявный оператор, чтобы я мог назначить его переменным перечисления (в моем случае мне пришлось привязать объект к значению ComboBox).

Вы можете использовать отражение для форматирования значений перечисления так, как вы хотите, в моем случае я извлекаю DisplayAttribute из значений перечисления (если они существуют).

Надеюсь, что это поможет.

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:

На всякий случай, я использую следующую функцию для получения значений enum, которые я использую для DataSource 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;
    }
}

Ответ 19

Как только у вас есть метод GetDescription (он должен быть глобальным статическим), вы можете использовать его с помощью метода расширения:

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

Ответ 20

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

Status = ReallyNice.GetDescription()

Ответ 21

Вы можете определить Enum как

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

а затем используйте HowNice.GetStringValue().