65.9K
CodeProject 正在变化。 阅读更多。
Home

ComboBox 扩展

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.89/5 (7投票s)

2013年11月8日

CPOL

3分钟阅读

viewsIcon

33600

downloadIcon

844

用于与 Enum 类型绑定的 ComboBox 扩展方法

引言

在我作为 GUI 程序员的职业生涯中,我曾无数次需要用程序中定义的某些 Enum 值来填充组合框。然后在用户选择后,我需要将选定的项翻译回相应的 Enum 值。我总是以丑陋且难以维护的代码告终,其中 Enum 值是通过 ComboBox 选定项索引或 string 值手动映射到 ComboBox 实例的。

我知道有更好的方法可以做到,但时间不足、懒惰、“以后再修”的态度阻止了我编写合适的解决方案。但够了。

C# 3.0 引入的扩展方法提供了一种非常便捷的方式来用额外的方法扩展现有类型。它简单而优雅,最重要的是,它非常容易与目标类型集成。您需要做的就是添加包含扩展的类的引用,并在代码中添加扩展命名空间的 using 指令。

代码解释

为了涵盖所需的功能,以下三个方法就足够了

  1. 将任何 Enum 类型绑定到 ComboBox 实例的方法。绑定后,ComboBox 实例应表现为底层 Enum 类型的 GUI 表示。换句话说,ComboBox 项应与 Enum 字段紧密相关。

    public static void BindWithEnum<T>(this ComboBox comboBox, T selectedValue) 

    selectedValue 参数决定了初始选定的 ComboBox 项。

  2. 检索当前选定的 ComboBox 项的方法。

    public static T GetSelectedValue<T>(this ComboBox comboBox)  
  3. 最后,更改 ComboBox 选定的方法。

    public static void SetSelectedValue<T>(this ComboBox comboBox,T selectedValue) 

    selectedValue 参数决定了新的选定 ComboBox 项。

BindWithEnum 方法

此方法使用反射来枚举给定 Enum 类型的所有字段。对于每个字段,它会检索 Description 属性,以便在 ComboBox 项中提供用户友好的文本。接下来,该方法将 Description 文本和与之关联的 Enum 值添加到 ComboBox 项列表中。ComboBox 成为底层 Enum 的紧密耦合的可视化表示。

public static void BindWithEnum<T>(this ComboBox comboBox, T selectedValue)
{
    Type enumType = typeof(T);
 
    if (!enumType.IsEnum)
       throw new Exception("Only Enum types are allowed.");
 
    //List containing ComboBox items.
    List<KeyValuePair<string, 
    T>> comboBoxItems = new List<KeyValuePair<string, T>>();
    //Temporary store for item that needs to be selected.
    KeyValuePair<string, T>? selectedItem = null;
 
    //Loop through all Enum values and build the list of ComboBox items.
    foreach (T enumValue in Enum.GetValues(enumType))
    {
       string name = Enum.GetName(enumType, enumValue);
       FieldInfo fi = enumType.GetField(name);
 
       string descriptiveName = fi.GetDescriptionAttributeOrName();
 
       KeyValuePair<string,T> item = 
       	new KeyValuePair<string,T>(descriptiveName,enumValue);
       comboBoxItems.Add(item);
 
       //If current loop enumValue is equal to the value that needs to be initially 
       //selected, store it in temporary location.
       if (enumValue.Equals(selectedValue))
          selectedItem = item;
    }
 
    //Set ComboBox values
    comboBox.DisplayMember = "Key";
    comboBox.ValueMember = "Value";
    comboBox.DataSource = comboBoxItems;
 
    //Set initial selection of the ComboBox
    if (selectedItem != null)
       comboBox.SelectedItem = selectedItem.Value;
} 
示例

以下代码将 Enum 类型 OptionsToSelectFrom comboBox1 绑定,并将 OptionsToSelectForm.Opt3 设为 comboBox1 中的选定项。

 comboBox1.BindWithEnum<OptionsToSelectFrom>(OptionsToSelectFrom.opt3); 

GetSelectedValue 方法

该方法检索与当前选定的 ComboBox 项关联的 Enum 值。

public static T GetSelectedValue<T>(this ComboBox comboBox)
{
   KeyValuePair<string, T> 
   selectedItem = (KeyValuePair<string, T>)comboBox.SelectedItem;
 
   return (T)Convert.ChangeType(selectedItem.Value, typeof(T));
}
示例
OptionsToSelectFrom selectedValue = 
	comboBox1.GetSelectedValue<OptionsToSelectFrom>();

SetSelectedValue 方法

此方法用于将选定的 ComboBox 项设置为提供的 Enum 值。

public static void SetSelectedValue<T>(this ComboBox comboBox,T selectedVaue)
{
   string name = Enum.GetName(typeof(T), selectedOption);
   FieldInfo fi = typeof(T).GetField(name);
   string descriptiveName = fi.GetDescriptionAttributeOrName();
 
   KeyValuePair<string, T> selectedItem = 
                 new KeyValuePair<string, T>(descriptiveName, selectedOption);
   comboBox.SelectedItem = selectedItem;
}  
示例
 comboBox1.SetSelectedValue<OptionsToSelectFrom>(OptionsToSelectFrom.opt2);

一些额外的功能

作为编写 ComboBoxExtensions 的“副作用”,我得到了一组小的 Type 相关扩展。最初,我将它们定义为 private 辅助方法,供 ComboboxExtensions 内部使用,但在考虑后,我得出结论,它们本身可能有一些价值,所以我决定将它们也公开为 public 扩展方法。

下面是它们的名称和用法示例。

TryGetDefaultValueAttribute 方法

此方法简化了给定类型的 DefaultValue 属性的检索。如果给定类型存在 DefaultValue ,则其值将通过 int out 参数返回,并且方法返回值为 true。如果给定类型不存在 DefaultValue 属性,则该方法返回 false ,并且输出参数的值是不确定的。

public static bool TryGetDefaultValueAttribute<T>(this Type type, out T defaultValue)
{
    DefaultValueAttribute[] defaultValueAttribute = 
    (DefaultValueAttribute[])type.GetCustomAttributes(typeof(DefaultValueAttribute),false);

    if (defaultValueAttribute.Length > 0)
    {
        defaultValue = (T)Convert.ChangeType(defaultValueAttribute[0].Value, typeof(T));
        return true;
    }
    else
    {
        defaultValue = Activator.CreateInstance<T>();
        return false;
    }
}    
示例
if (!typeof(OptionsToSelectFrom).
      TryGetDefaultValueAttribute<OptionsToSelectFrom>(out defValue))
{
   MessageBox.Show("Type does not have DefaultValue attribute");
} 

GetDefaultValueAttribute

此方法以与 TryGetDefaultValueAttribute 类似的方式检索 DefaultValue 属性。如果属性不存在,该方法将引发异常。

public static T GetDefaultValueAttribute<T>(this Type type)
{
   T retValue;
   if (type.TryGetDefaultValueAttribute<T>(out retValue))
      return retValue;
   else
      throw new Exception"No DefaultValue associated with the type.", type.ToString()));
}

GetDescriptionAttributeOrName

此方法检索给定 enum 值的 Description 属性的值。如果 Description 属性不存在,则该方法返回字段名称。

public static string GetDescriptionAttributeOrName(this Enum value)
{
    Type type = value.GetType();
    string name = Enum.GetName(type, value);
    FieldInfo fi = type.GetField(name);
    return fi.GetDescriptionAttributeOrName();
}

Using the Code

非常简单。

  1. 在您的项目中,添加对 ComboBoxExttensions.dll 的引用
  2. 在代码中添加以下 using 指令: using Proxoft.WinForms;
  3. 您就可以开始使用了。下面的代码片段展示了如何将 Enum ComboBox 绑定以及如何设置和检索当前选定项。您还可以下载源代码和演示程序,熟悉扩展功能。

以下代码片段展示了大多数用例

//This is the namespace where extension is defined
using Proxoft.WinForms;
 
(..)
 
//Structure that will bind with ComboBox

    [DefaultValue(OptionsToSelectFrom.opt3)]
    public enum OptionsToSelectFrom
    {
        [Description("Option One")]
        opt1,
        [Description("Option Two")]
        opt2,
        [Description("Option Three")]
        opt3,
        [Description("Option Four")]
        opt4
    }
 
(...)
 
//The following line binds 'OptionsToSelectFrom' enum with comboBox1.
//Initially selected comboBox value will be set to 'OptionsToSelectFrom.opt3'.  

 comboBox1.BindWithEnum<OptionsToSelectFrom>(OptionsToSelectFrom.opt3); 
 
(...)
 
//The following line of code changes selection to 'OptionsToSelectFrom.opt2'.
 
<span style="font-size: 9pt;">comboBox1.SetSelectedValue
<OptionsToSelectFrom>(OptionsToSelectFrom.opt2);  
</span>
<pre lang="cs">(...)
 
//The following line shows how to examine currently selected value
 
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
    label1.Text =  comboBox1.GetSelectedValue<OptionsToSelectFrom>().ToString();
}  

历史

  • 2013 年 11 月 7 日 - 初始文章发布
© . All rights reserved.