【问题标题】:C# Globals/Constants bindable to DDLs, but with "Nice" namesC# Globals/Constants 可绑定到 DDL,但具有“好”的名称
【发布时间】:2011-07-20 14:46:08
【问题描述】:

出于通常的原因,我需要在我的应用程序中使用一些常量。

我考虑过的方法:

1) 声明一个枚举:

public enum myOptions
{
  MyOption1 = 72,
  MyOption2 = 31,
  MyOption3 = 44
}

虽然这很适合编程,而且我可以将枚举直接绑定到 DDL,但是当用户看到枚举“名称”时它们很难看 - 用户将看到“MyOption1”,我希望他们看到“我的选项 #1"。

2) 使用列表:

public static List<KeyValuePair<int, string>> myOptions = new List<KeyValuePair<int, string>>
{
 new KeyValuePair<int, string>(77, "My Option #1"),
 new KeyValuePair<int, string>(31, "My Option #2"),
 new KeyValuePair<int, string>(44, "My Option #3")
}

因此,虽然这很好地绑定到 DDL,给了我一个很好的显示值以及一个整数返回值,但我没有任何东西可以测试我的返回值。所以,例如:

if (selectedOption=????) //I'd have to hardcode the Key or Value I want to test for.

3) 我可以构建好的全局/常量程序集:

static myOptions
{
 public static KeyValuePair<int, string> MyOption1 = new new KeyValuePair<int, string>(77, "My Option #1");
 public static KeyValuePair<int, string> MyOption2 = new new KeyValuePair<int, string>(31, "My Option #2");
 public static KeyValuePair<int, string> MyOption3 = new new KeyValuePair<int, string>(44, "My Option #3");
}

这给了我很好的显示名称,很适合编写代码,但据我所知,我无法轻松地将它绑定到 DDL(我必须手动编写代码)。

有没有人有一种优雅的方式来创建易于绑定到 DDL 的常量,我可以在其中有一个漂亮的显示名称?

现在我唯一能想到的就是同时构建枚举和列表,这似乎很烦人。

【问题讨论】:

    标签: c# enums constants global


    【解决方案1】:

    我总是倾向于装饰枚举值:

    public enum myOptions
    {
        [Description("My Option #1")]
        MyOption1 = 72,
        [Description("My Option #2")]
        MyOption2 = 31,
        [Description("My Option #3")]
        MyOption3 = 44
    }
    

    或者更好的是,您可以创建一个绑定到资源文件或配置设置的自定义属性,以便无需重新编译即可更改此数据

    public enum myOptions
    {
        [Custom("MyOption1Key")]
        MyOption1 = 72,
        [Custom("MyOption2Key")]
        MyOption2 = 31,
        [Custom("MyOption3Key")]
        MyOption3 = 44
    }
    

    更新以从枚举中提取属性

    public static T GetAttribute<T>(this Enum e) where T : Attribute
    {
        FieldInfo fieldInfo = e.GetType().GetField(e.ToString());
        T[] attribs = fieldInfo.GetCustomAttributes(typeof(T), false) as T[];
        return attribs.Length > 0 ? attribs[0] : null;
    }
    

    【讨论】:

    • 你建议我如何将修饰的枚举绑定到 DDL?
    • 从枚举中提取属性
    • 我的印象是,我必须遍历枚举以提取每个描述。有没有办法直接绑定?我希望与键值对列表有类似的东西,我只是设置 ddl.DataSource = new BindingSource(myKVPList, null);
    • 抱歉 - 刚刚注意到您提出的提取方法的更新。感谢您的帮助!
    • 小心反射...如果使用不当,它可能会非常缓慢。
    【解决方案2】:

    根据@hunter 提供的答案,我决定发布我的完整实现,因为我花了一段时间才把它弄好(还在这里学习......)

    // This is the class I used to hold the extensions.
    public static class EnumFunctions
    {
        // Custom GetAttribute Extension - used to pull an attribute out of the enumerations.
        // This code is as per Hunter's answer, except I added the null check.
        public static T GetAttribute<T>(this Enum e) where T : Attribute
        {
            FieldInfo fieldInfo = e.GetType().GetField(e.ToString());
    
            // If the enumeration is set to an illegal value (for example 0,
            // when you don't have a 0 in your enum) then the field comes back null.
            // test and avoid the exception.
            if (fieldInfo != null)
            {
                T[] attribs = fieldInfo.GetCustomAttributes(typeof(T), false) as T[];
                return attribs.Length > 0 ? attribs[0] : null;
            }
            else
            {
                return null;
            }
        }
    
        // Custom GetKeyValuePairs - returns a List of <int,string> key value pairs with
        // each Enum value along with it's Description attribute.
        // This will only work with a decorated Enum. I've not included or tested what
        // happens if your enum doesn't have Description attributes.
        public static List<KeyValuePair<int, string>> GetKeyValuePairs(this Enum e)
        {
            List<KeyValuePair<int, string>> ret = new List<KeyValuePair<int, string>>();
    
            foreach (Enum val in Enum.GetValues(e.GetType()))
            {
                ret.Add(new KeyValuePair<int, string>(Convert.ToInt32(val), val.GetAttribute<DescriptionAttribute>().Description));
            }
            return ret;
        }
    
    }
    

    在其他地方,要绑定到 DDL,您可以简单地这样做:

    {
        // We need an instance of the enum to call our extension method.
        myOptions o = myOptions.MyOption1;
    
        // Clear the combobox
        comboBox1.DataSource = null;
        comboBox1.Items.Clear();
    
        // Bind the combobox
        comboBox1.DataSource = new BindingSource(o.GetKeyValuePairs(), null);
        comboBox1.DisplayMember = "Value";
        comboBox1.ValueMember = "Key";      
    }
    

    最后,要提取选定的值,您可以这样做:

    {
        // Get the selected item in the combobox
        KeyValuePair<int, string> selectedPair = (KeyValuePair<int, string>)comboBox1.SelectedItem;
    
        //I'm just sticking the values into text labels to demonstrate.
        lblSelectedKey.Text = selectedPair.Key.ToString();
        lblSelectedValue.Text = selectedPair.Value.ToString();
    }
    

    ..我并没有就此止步。我扩展了 ComboBox 控件本身,所以现在绑定它非常方便。

        // Extends the Combobox control so that it can be automatically bound to an Enum
        // that has been decorated with Description attributes.
        // Sets the current value of the combobox to the value of the enum instance passed in.
        public static void BindToDecoratedEnum(this System.Windows.Forms.ComboBox cb, Enum e)
        {
            // Clear the combobox
            cb.DataSource = null;
            cb.Items.Clear();
    
            // Bind the combobox
            cb.DataSource = new System.Windows.Forms.BindingSource(e.GetKeyValuePairs(), null);
            cb.DisplayMember = "Value";
            cb.ValueMember = "Key";
    
            cb.Text = e.GetAttribute<DescriptionAttribute>().Description;
        }
    

    所以现在,每当我想填充 DDL 时,我只需:

            myDDL.BindToDecoratedEnum(myEnumInstanceWithValue);
    

    代码绑定它,并选择与传入的Enum的当前值匹配的项。

    欢迎对我的实施提出评论和批评(实际上,我会很感激 - 就像我说的,我正在努力学习......)

    【讨论】:

    • +1 不错,我相信你可以在这里和那里重构,但总体上还不错
    【解决方案3】:

    另一个建议?

    public static List<KeyValuePair<int, string>> GetKeyValuePairs<T>()
        {
            Type enumType = typeof(T);
    
            List<KeyValuePair<int, string>> ret = new List<KeyValuePair<int, string>>();
            foreach (Enum val in Enum.GetValues(enumType))
            {
                ret.Add(
                    new KeyValuePair<int, string>(Convert.ToInt32(val),
                    val.GetAttribute<DescriptionAttribute>().Description)
                    );
            } return ret;
        }
    

    然后您可以绑定而无需创建枚举的实例。它是您想要了解的枚举类型,而不是特定实例)

    ddlPes.DataSource = EnumHelper.GetKeyValuePairs<PesId>();
    ddlPes.DataValueField = "key";
    ddlPes.DataTextField = "value";
    ddlPes.DataBind();
    

    【讨论】:

      猜你喜欢
      • 2013-09-26
      • 2018-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-04
      • 2013-11-29
      相关资源
      最近更新 更多