【问题标题】:.NET databinding a combobox to a string enum with Description attributes.NET 将组合框数据绑定到具有描述属性的字符串枚举
【发布时间】:2011-10-18 17:52:00
【问题描述】:

我有一个这样的枚举:

public enum Cities
{
    [Description("New York City")]
    NewYork,
    [Description("Los Angeles")]
    LosAngeles,
    Washington,
    [Description("San Antonio")]
    SanAntonio,
    Chicago
}

我想将它绑定到一个组合框,我已经尝试过了:

comboBox.DataSource = Enum.GetNames(typeof(Cities));

但这会在组合框中显示值而不是字符串描述。所以我切换到这个:

public static string GetEnumDescription(Enum value)
{
    FieldInfo fi = value.GetType().GetField(value.ToString());

    DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);

    if (attributes != null && attributes.Length > 0)
    {
        return attributes[0].Description;
    }
    else
    {
        return value.ToString();
    }
}

public static IList ToList(this Type type)
{
    ArrayList list = new ArrayList();
    Array enumValues = Enum.GetValues(type);

    foreach (Enum value in enumValues)
    {
        list.Add(new KeyValuePair<Enum, string>(value, GetEnumDescription(value)));
    }

    return list;
}

现在 list.Add() 调用会产生值,它的字符串描述显示在组合框中,所以我替换了

list.Add(new KeyValuePair<Enum, string>(value, GetEnumDescription(value)));

list.Add(GetEnumDescription(value));

现在我得到的只是组合框中显示的描述性字符串,这是我最终想要的。现在我的数据绑定被破坏了,因为它无法在枚举中找到字符串描述。我认为这可能与 combobox.DisplayMember 和 combobox.ValueMember 有关,但我还没有解决这个问题。谁能告诉我如何显示描述性字符串但让我的数据绑定使用该值进行存储等?谢谢!!!

【问题讨论】:

  • 只是出于好奇..为什么要为此使用枚举?
  • 我需要显示几个包含不同固定选项的组合框供我的用户选择。也许有一个组合框可以显示四种颜色(红、黄、绿、蓝)。另一个可能会显示一个形状列表供他们选择。由于这些是固定列表,我认为枚举是有意义的。我有一个“数据”类来模拟所有这些东西,当用户在 UI 中完成选择后,我只需解析数据对象的属性并将值保存到文件中。这能回答你的问题吗?
  • 是的,它会按照你的方式正常工作,只是让代码变得更棘手。既然这是一个硬编码列表,那么在运行时实例化一个硬编码列表作为替代方案会有什么缺点?
  • 我认为这不会有任何缺点。我只是试图让我的数据类中的所有内容都保持整洁,并在此过程中了解有关枚举和数据绑定的更多信息。 :-)

标签: .net winforms data-binding combobox enumeration


【解决方案1】:

让我们回到几天前我answered 的问题,并对其进行修改以适应您的新要求。因此,我将在此问题中保留 colorEnum 示例代替您的 Cities 枚举。

您已经完成了大部分工作 - 您已经获得了从枚举到描述字符串的代码;现在你只需要回到另一条路。

public static class EnumHelper
{
    // your enum->string method (I just decluttered it a bit :))
    public static string GetEnumDescription(Enum value)
    {
        var fi = value.GetType().GetField(value.ToString());
        var attributes = fi.GetCustomAttributes(typeof(DescriptionAttribute), false);

        if (attributes.Length > 0)
            return ((DescriptionAttribute)attributes[0]).Description;
        else
            return value.ToString();        
    }

    // the method to go from string->enum
    public static T GetEnumFromDescription<T>(string stringValue)
        where T : struct
    {
        foreach (object e in Enum.GetValues(typeof(T)))           
            if (GetEnumDescription((Enum)e).Equals(stringValue))
                return (T)e;
        throw new ArgumentException("No matching enum value found.");
    }

    // and a method to get a list of string values - no KeyValuePair needed
    public static IEnumerable<string> GetEnumDescriptions(Type enumType)
    {
        var strings = new Collection<string>();
        foreach (Enum e in Enum.GetValues(enumType))   
            strings.Add(GetEnumDescription(e));
        return strings;
    }
}

现在,拿你几天前的东西......

public class Person 
{
    [...]
    public colorEnum FavoriteColor { get; set; }
    public string FavoriteColorString
    {
        get { return FavoriteColor.ToString(); }
        set { FavoriteColor = (colorEnum)Enum.Parse(typeof(colorEnum), value);  }
    }
}

只需将其更改为:

public class Person 
{
    [...]
    public colorEnum FavoriteColor { get; set; }
    public string FavoriteColorString
    {
        get { return EnumHelper.GetEnumDescription(FavoriteColor); }
        set { FavoriteColor = EnumHelper.GetEnumFromDescription<colorEnum>(value); }
    }
}

和以前一样,您将组合框SelectedItem 的值绑定到FavoriteColorString。如果您仍在使用 BindingSource,则无需设置 DisplayMember 或 ValueMember 属性,就像在另一个问题中一样,我假设您是。

并从以下位置更改组合框填充代码:

comboBoxFavoriteColor.DataSource = Enum.GetNames(typeof(colorEnum));

comboBoxFavoriteColor.DataSource = EnumHelper.GetEnumDescriptions(typeof(colorEnum));

现在你拥有了世界上最好的。用户看到描述,您的代码包含枚举名称,数据存储包含枚举值。

【讨论】:

  • 在过去一周左右的时间里,您给了我很多很好的答案,我非常感谢您的帮助和解释。一如既往,感谢您分享您的专业知识!
  • @user68:不客气。顺便说一句,我在GetEnumDescription() 中删除了attributes != null 检查的原因是GetCustomAttributes() 在没有找到任何属性时只是返回一个空数组。
  • @user68: 还有一件事......你可以支持我的答案并接受它们。我很感激我能赢得的任何代表。 :)
  • 感谢您指出点赞功能!我现在就为你的所有答案都这样做!
  • 向我们展示,@Hamish!还有另一种选择 - 使用 Binding 类上的 FormatParse 事件在枚举值和动态描述之间进行转换。这样你就不需要 Person 类的额外属性。到目前为止,我在使用这种方法时遇到了一些奇怪的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-05
  • 2010-09-08
  • 1970-01-01
  • 2018-12-18
相关资源
最近更新 更多