[C#] 열거 형 값에 대한 사용자 지정 문자열 형식을 가진 열거 형 콤보 상자를 사용하려면 어떻게합니까?

Post Enum ToString 에서 메소드는 다음 DescriptionAttribute과 같이 사용자 정의 속성을 사용하도록 설명됩니다 .

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

그런 다음 다음 GetDescription과 같은 구문을 사용하여 function을 호출합니다 .

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

그러나 ComboBox를 강제로 호출 할 수 없기 때문에 단순히 열거 형 값으로 ComboBox를 채우려는 경우GetDescription 실제로 도움이되지 않습니다 .

내가 원하는 것은 다음 요구 사항이 있습니다.

  • 판독 (HowNice)myComboBox.selectedItem하면 선택한 값이 열거 형 값으로 반환됩니다.
  • 열거 값의 이름뿐만 아니라 사용자에게 친숙한 표시 문자열이 표시되어야합니다. 따라서 ” NotNice” 를 보는 대신 ” “가 표시 Not Nice At All됩니다.
  • 다행히 솔루션이 기존 열거에 대한 코드 변경을 최소화해야합니다.

분명히, 내가 만든 각 열거 형에 대해 새로운 클래스를 구현하고 재정의 할 수 ToString()는 있지만 각 열거 형에 많은 작업이 필요하므로 오히려 피해야합니다.

어떤 아이디어?

도대체, 나는 현상금 으로 포옹 을 던질 것입니다 🙂



답변

지정된 속성을 읽어 리소스에서 찾아 보는 TypeConverter를 작성할 수 있습니다. 따라서 많은 번거 로움없이 표시 이름에 대한 다국어 지원을받을 수 있습니다.

TypeConverter의 ConvertFrom / ConvertTo 메서드를 살펴보고 리플렉션을 사용하여 열거 형 필드의 특성을 읽습니다 .


답변

ComboBoxFormattingEnabled설정해야하는 속성 trueFormat원하는 형식 지정 로직을 배치해야하는 이벤트 등 필요한 모든 것이 있습니다 . 그러므로,

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


답변

하지마! 열거 형은 UI 객체가 아닌 프리미티브이며, .ToString ()에서 UI를 제공하도록 만드는 것은 디자인 관점에서 상당히 나쁩니다. 여기에서 잘못된 문제를 해결하려고합니다. 실제 문제는 Enum.ToString ()이 콤보 상자에 나타나지 않게하는 것입니다!

이제 이것은 실제로 매우 해결 가능한 문제입니다! 콤보 상자 항목을 나타내는 UI 객체를 만듭니다.

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

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

그런 다음이 클래스의 인스턴스를 콤보 상자의 Items 컬렉션에 추가하고 다음 속성을 설정하십시오.

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


답변

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(). 그동안이 문제를 해결하겠다고 생각합니다.


답변

열거 형 예제 사용 :

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에게갑니다


답변

설명이있는 모든 열거 형에 사용할 수있는 일반적인 구조체를 만들 수 있습니다. 클래스와의 암시 적 변환을 통해 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"


답변

최소한 다른 유형에 바인딩하지 않고는 할 수 있다고 생각하지 않습니다. 적어도 편리하지는 않습니다. 일반적으로 제어 할 수없는 경우에도 ToString()a TypeConverter를 사용하여 사용자 정의 형식을 지정할 수 있지만 IIRC는 System.ComponentModel열거 형에 대해 이것을 존중하지 않습니다.

string[]설명 중 하나 또는 본질적으로 키 / 값 쌍과 같은 것에 바인딩 할 수 있습니까? (설명 / 값)-다음과 같은 것 :

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()