如何使用枚举值的自定义字符串格式设置枚举绑定组合框?


135

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时GetDescription,这并没有真正帮助我,因为我不能强制ComboBox调用

我要具有以下要求:

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

显然,我可以为我创建的每个枚举实现一个新类,并覆盖它的ToString(),但是每个枚举都需要大量工作,因此我宁愿避免这种情况。

有任何想法吗?

哎呀,我什至会拥抱一个赏金:-)


1
jjnguy是正确的,Java枚举很好地解决了这个问题(javahowto.blogspot.com/2006/10/…),但这是值得怀疑的。
马修·弗莱申

8
Java枚举是一个笑话。也许他们会在2020年添加Properties:/
Chad Grant

有关较轻(但可以说不那么健壮)的解决方案,请参见我的主题
Gutblender14 2014年

Answers:


42

您可以编写一个TypeConverter来读取指定的属性,以便在您的资源中查找它们。因此,您将获得对显示名称的多语言支持,而无需太多麻烦。

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


好的,我写了一些代码(请参阅我对这个问题的回答)-您是否认为就足够了,我还缺少什么吗?
Shalom Craimer 09年

1
好一个。更好的总体表现,但是对于您永不过时的全球化软件来说,这可能是过大的选择。(我知道,这个假设以后会变成错误的。;
peSHIr

85

ComboBox具有所需的一切:FormattingEnabled属性(应设置为true)和Format事件(需要在其中放置所需的格式逻辑)。从而,

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

这仅适用于数据绑定组合框吗?否则,我无法触发Format事件。
SomethingBetter

唯一的问题是您无法按照逻辑对列表进行排序
GorillaApe 2015年

这是一个很好的解决方案。我需要它与DataGridComboBoxColumn虽然。有机会解决吗?我找不到找到访问的ComboBox方法DataGridComboBoxColumn
索科

46

别!枚举是基元,而不是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";

1
我完全同意。您也不应向用户界面公开ToString()的结果。而且,您不会本地化。
岛之风Skaar

我知道这很老了,但是有什么不同呢?
nportelli

2
我已经看到了类似的解决方案,其中他们不使用自定义类,而是将枚举值映射到Dictionary,并将KeyValue属性用作DisplayMemberValueMember
杰夫·B

42

TypeConverter。我想这就是我想要的。所有人都欢呼西蒙·斯文森(Simon Svensson)

[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()。我想我会为此而安顿下来...


3
您正在处理Enum-> String,但是如果需要完整的实现,还需要Enum> InstanceDescriptor和String-> Enum。但我想现在显示它足以满足您的需求。;)
sisve

1
不幸的是,该解决方案仅在您的描述是静态的时才有效。
Llyle

顺便说一句,TypeConverter的使用不限于静态描述,掩体可以从属性以外的其他来源填充​​值。
德米特里·塔什基诺夫

3
现在已经拉了我几个小时了,但是即使在简单的控制台应用程序中,它似乎仍然无法正常工作。我用修饰了枚举[TypeConverter(typeof(EnumToStringUsingDescription))] public enum MyEnum {[Description("Blah")] One},尝试这样做Console.WriteLine(MyEnum.One),但仍然显示为“一个”。您是否需要某种特殊的魔术TypeDescriptor.GetConverter(typeof(MyEnum)).ConvertToString(MyEnum.One)(效果很好)?
DAV

1
@scraimer我已经发布了支持标志的代码版本。保留所有权利……
Avi Turner

32

使用您的枚举示例:

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


我在引用的站点上跟踪了详细信息,并按如下方式使用了它,对我来说看起来很简单:“字符串myDesc = HowNice.ReallyNice.Description();” myDesc将输出“真的很好”
Ananda

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

}

用法示例:

Described<HowNice> nice = HowNice.ReallyNice;

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

5

我认为,如果不简单地绑定到其他类型,就无法做到这一点-至少是不方便的。通常,即使您无法控制ToString(),也可以使用TypeConverter做自定义格式-但IIRCSystem.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()


1
名称“ GetDescription”在当前上下文中不存在。即时通讯使用.NET 4.0
Muhammad Adeel Zahid 2012年

@MuhammadAdeelZahid仔细看问题的开头-来自链接的文章:stackoverflow.com/questions/479410/enum-tostring
Marc Gravell

抱歉,无法从问题中获得任何线索。您的方法未编译并显示错误。
Muhammad Adeel Zahid 2012年

马克,您好,我尝试了您的想法。它正在工作,但是theComboBox.SelectItem是类型EnumWrapper<T>,而不是T本身。我认为斯克赖默想要Reading (HowNice)myComboBox.selectedItem will return the selected value as the enum value.
彼得·李

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

我相信这是最好的方法。

当将其填充到组合框中时,将显示漂亮的ToString,而实际上没有人可以再创建您的类的更多实例这一事实实际上使它成为枚举。

ps可能需要一些轻微的语法修复,我对C#不太满意。(Java家伙)


1
这对组合框问题有何帮助?
peSHIr

好了,现在,当将新对象放入组合框中时,它将正确显示其ToString,并且该类仍然像枚举一样工作。
jjnguy

1
也会是我的答案。
Mikko Rantanen

3
并查看原始张贴者如何明确地不希望上课。我认为一堂课没有那么多工作。您可以将描述抽象化,并将ToString重写为所有枚举的父类。在这之后,您需要的是构造函数private HowNice(String desc) : base(desc) { }和静态字段。
Mikko Rantanen

我希望避免这种情况,因为这意味着我进行的每个枚举都需要自己的类。啊。
Shalom Craimer 09年

3

考虑到您不想为每个枚举创建一个类,我建议创建一个包含枚举值/显示文本的字典并将其绑定。

请注意,这与原始文章中的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;
}

好主意。但是,如何将其与组合框一起使用?一旦用户从组合框中选择了一个项目,我如何知道他选择了哪个项目?通过描述字符串搜索?这使我的皮肤发痒...(描述字符串之间可能有字符串“碰撞”)
Shalom Craimer 09年

所选项目的键将是实际的枚举值。另外,请勿冲突描述字符串-用户将如何区分差异?
理查德·萨雷

<cont>如果描述字符串冲突,则无论如何都不应将枚举的值直接绑定到组合框。
理查德·萨雷

嗯...好吧,能否给我示例代码,说明如何将项目添加到组合框?我只能想到的是“ foreach(descriptionDict.Values中的字符串s){this.combobox.Items.Add(s);}”
Shalom Craimer 09年

1
ComboBox.DataSource =字典;
理查德·萨雷

3

无法覆盖C#中的枚举的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语句和所有内容-但它应该可以正常工作,并且希望可以避免许多重写...


请注意,绑定到枚举的控件不会调用此扩展方法,而是会调用默认实现。
理查德·萨雷

对。因此,如果您需要在某处进行说明,那么这是一个可行的选择,它对解决组合框问题没有帮助。
peSHIr

更大的问题是,它将永远不会被调用(作为扩展方法)-已经存在的实例方法始终具有优先权。
Marc Gravell

马克当然是对的(一如既往?)。我的.NET经验很少,但是为该方法提供虚拟参数应该可以解决问题。编辑答案。
比约恩

2

在@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'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;
    }

}

以及使用它的扩展方法:

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

1

我会写一个通用类,用于任何类型。我过去曾使用过类似的方法:

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
}

最重要的是,您可以添加一个静态的“工厂方法”以创建给定枚举类型的组合框项目列表(与那里的GetDescriptions方法几乎相同)。这将节省您不必为每种枚举类型实现一个实体,并且还为“ GetDescriptions”帮助器方法提供了一个不错的/逻辑的位置(我个人称其为FromEnum(T obj)...


1

创建一个包含所需内容的集合(例如,简单的对象包含一个Value包含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; } }
    }

}

如您所见,可以使用lambda轻松定制此集合,以选择枚举器的子集和/或实现自定义格式,string而不使用GetDescription<T>(x)您提到的功能。


很好,但是我正在寻找一些需要更少的代码工作的东西。
Shalom Craimer 09年

即使您可以对所有枚举器都使用相同的通用集合进行此类操作?我当然不建议习惯为每个枚举编写这样的集合。
peSHIr

1

您可以使用PostSharp定位Enum.ToString并添加所需的aditionall代码。这不需要任何代码更改。


1

您需要将一个枚举转换为ReadonlyCollection并将该集合绑定到组合框(或与此相关的任何启用键值对的控件)

首先,您需要一个包含列表项的类。因为您只需要一个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属性是显式实现的(因此该类可以具有任何属性,您可以选择实现该属性的属性)键/值对。

现在,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输入,因此如果您绑定到适当的属性,则组合框值应返回一个枚举值。

我添加了T this [Enum t]属性,以使该集合比简单的组合式消耗品更加有用,例如,textBox1.Text = enumcol [HowNice.ReallyNice] .NicenessDescription;。

当然,您可以选择将MyItem变成仅用于此对象的Key / Value类,从而有效地完全跳过了EnumToReadnlyCollection的类型参数中的MyItem,但是随后您将不得不使用int作为键(这意味着获取combobox1.SelectedValue将返回int而不是enum类型)。如果创建KeyValueItem类来替换MyItem等,则可以解决此问题。


1

抱歉,这个旧线程启动了。

我将采用以下方式对枚举进行本地化,因为在此示例中,它可以通过下拉列表文本字段向用户显示有意义且本地化的值,而不仅仅是描述。

首先,我创建一个名为OwToStringByCulture的简单方法,以从全局资源文件中获取本地化的字符串,在本示例中,它是App_GlobalResources文件夹中的BiBongNet.resx。在此资源文件中,请确保所有字符串都与枚举的值相同(ReallyNice,SortOfNice,NotNice)。在此方法中,我传入参数:resourceClassName,通常是资源文件的名称。

接下来,我创建一个静态方法来填充下拉列表,并用enum作为其数据源,称为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'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);
        }
}

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

简单的代码和快速的解码。


字符串变量应该是静态和像这样宣称:静态字符串[]字符串=新[] {...}
塞尔吉奥

唯一的问题是,每个枚举都需要有一个函数,并且说明将不包含枚举本身...
Avi Turner

1

我尝试了这种方法,它为我工作。

我为枚举创建了包装器类,并重载了隐式运算符,以便可以将其分配给枚举变量(在本例中,我必须将对象绑定到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);
    }
}

编辑:

为以防万一,我用下面的函数获取enum值,我使用了DataSourceComboBox

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

0

一旦有了GetDescription方法(它必须是全局静态的),就可以通过扩展方法使用它:

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

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

Status = ReallyNice.GetDescription()

3
欢迎来到stackoverflow!最好为示例代码提供简短的描述,以提高发布的准确性:)
Picrofo Software 2012年

-1

您可以将Enum定义为

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

然后使用HowNice.GetStringValue()


2
这不能编译(我有.NET 3.5)。“ StringValue”在哪里声明?
敬畏

1
@scraimer的答案是相同的,除了他使用的是框架之外的属性,而您使用的是某种自定义属性。
奥利弗
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.