如何为enum值设置枚举绑定组合框以及自定义字符串格式?

Sha*_*mer 134 c# enums combobox

在帖子Enum ToString中,描述了一个方法来使用自定义属性,DescriptionAttribute如下所示:

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

然后,GetDescription使用如下语法调用函数:

GetDescription<HowNice>(NotNice); // Returns "Not Nice At All"
Run Code Online (Sandbox Code Playgroud)

但是,当我想简单地使用枚举值填充ComboBox时GetDescription,这并没有真正帮助我,因为我不能强制ComboBox调用.

我想要的是有以下要求:

  • 读取(HowNice)myComboBox.selectedItem将返回所选值作为枚举值.
  • 用户应该看到用户友好的显示字符串,而不仅仅是枚举值的名称.因此NotNice,用户不会看到" Not Nice At All" 而是看到" ".
  • 希望解决方案需要对现有枚举进行最少的代码更改.

显然,我可以为我创建的每个枚举实现一个新类,并覆盖它ToString(),但这对每个枚举来说都是很多工作,我宁愿避免这样做.

有任何想法吗?

哎呀,我甚至会一个拥抱作为赏金:-)

Ant*_*lev 85

ComboBox有你需要的一切:FormattingEnabled属性,你应该设置为trueFormat事件,在那里你会需要将所需的格式逻辑.从而,

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

  • 这很酷.但它在Silverlight中不存在:-) (2认同)

San*_*der 45

别!枚举是原始的而不是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; }
}
Run Code Online (Sandbox Code Playgroud)

然后只需将此类的实例添加到组合框的Items集合中并设置以下属性:

comboBox.ValueMember = "Value";
comboBox.DisplayMember = "Description";
Run Code Online (Sandbox Code Playgroud)

  • 我已经看到了类似的[溶液](http://msmvps.com/blogs/deborahk/archive/2009/07/10/enum-binding-to-the-description-attribute.aspx),其中,代替使用自定义在类中,他们将枚举值映射到`Dictionary`,并使用`Key`和`Value`属性作为`DisplayMember`和`ValueMember`. (2认同)

sis*_*sve 42

您可以编写一个TypeConverter来读取指定的属性以在资源中查找它们.因此,您可以毫不费力地获得显示名称的多语言支持.

查看TypeConverter的ConvertFrom/ConvertTo方法,并使用反射来读取枚举字段中的属性.


Sha*_*mer 42

类型转换器.我想这就是我在寻找的东西.所有的欢呼Simon Svensson!

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

我需要在当前枚举中更改所有内容,在声明之前添加此行.

[TypeConverter(typeof(EnumToStringUsingDescription))]
Run Code Online (Sandbox Code Playgroud)

一旦我这样做,任何枚举将使用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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这有助于我使用我的ComboBox案例,但显然实际上并没有覆盖ToString().我想我会同时满足于此......

  • 现在已经把我的头发拉了几个小时,但即使在简单的控制台应用程序中它仍然似乎不起作用.我使用`[TypeConverter(typeof(EnumToStringUsingDescription))]公开枚举MyEnum {[Description("Blah")] One}`来装饰enum,尝试做`Console.WriteLine(MyEnum.One)`它仍然出现为"一".你需要一些特殊的魔法,比如`TypeDescriptor.GetConverter(typeof(MyEnum)).ConvertToString(MyEnum.One)`(它确实工作正常)? (3认同)
  • 你正在处理Enum - > String,但如果你想要一个完整的实现,你还需要Enum> InstanceDescriptor和String - > Enum.但我想现在显示它已足以满足您的需求.;) (2认同)

Tyl*_*den 31

使用枚举示例:

using System.ComponentModel;

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

创建扩展:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以使用类似下面的内容:

HowNice myEnum = HowNice.ReallyNice;
string myDesc = myEnum.Description();
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参阅:http://www.blackwasp.co.uk/EnumDescription.aspx.感谢Richrd Carr的解决方案


Guf*_*ffa 8

您可以创建一个通用结构,您可以将其用于包含描述的所有枚举.通过对类的隐式转换,除了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;
    }

}
Run Code Online (Sandbox Code Playgroud)

用法示例:

Described<HowNice> nice = HowNice.ReallyNice;

Console.WriteLine(nice == HowNice.ReallyNice); // writes "True"
Console.WriteLine(nice); // writes "Really Nice"
Run Code Online (Sandbox Code Playgroud)


jjn*_*guy 5

这样做的最好方法是上课.

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!");
}
Run Code Online (Sandbox Code Playgroud)

我相信这是最好的方法.

当填充组合框时,将显示漂亮的ToString,并且没有人可以再创建您的类的实例,这实际上使它成为枚举.

ps可能需要一些轻微的语法修复,我对C#不是很好.(爪哇人)

  • 并且看到原始海报明确地不想要一堂课.我不认为班级是那么多工作.您可以抽象描述,并将ToString覆盖到所有枚举的父类.在此之后你需要的是一个构造函数`private HowNice(String desc):base(desc){}`和静态字段. (3认同)

Mar*_*ell 5

我不认为你能做到这一点而不仅仅是绑定到另一种类型 - 至少,不方便.通常情况下,即使你无法控制ToString(),你也可以使用a 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));
    }
}
Run Code Online (Sandbox Code Playgroud)

然后绑定到 EnumWrapper<HowNice>.GetValues()