ComboBox 扩展






4.89/5 (7投票s)
用于与 Enum 类型绑定的 ComboBox 扩展方法
引言
在我作为 GUI 程序员的职业生涯中,我曾无数次需要用程序中定义的某些 Enum
值来填充组合框。然后在用户选择后,我需要将选定的项翻译回相应的 Enum
值。我总是以丑陋且难以维护的代码告终,其中 Enum
值是通过 ComboBox
选定项索引或 string
值手动映射到
实例的。ComboBox
我知道有更好的方法可以做到,但时间不足、懒惰、“以后再修”的态度阻止了我编写合适的解决方案。但够了。
C# 3.0 引入的扩展方法提供了一种非常便捷的方式来用额外的方法扩展现有类型。它简单而优雅,最重要的是,它非常容易与目标类型集成。您需要做的就是添加包含扩展的类的引用,并在代码中添加扩展命名空间的 using
指令。
代码解释
为了涵盖所需的功能,以下三个方法就足够了
- 将任何
Enum
类型绑定到ComboBox
实例的方法。绑定后,ComboBox
实例应表现为底层Enum
类型的 GUI 表示。换句话说,ComboBox
项应与Enum
字段紧密相关。public static void BindWithEnum<T>(this ComboBox comboBox, T selectedValue)
selectedValue
参数决定了初始选定的ComboBox
项。 - 检索当前选定的
ComboBox
项的方法。public static T GetSelectedValue<T>(this ComboBox comboBox)
- 最后,更改
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
非常简单。
- 在您的项目中,添加对 ComboBoxExttensions.dll 的引用
- 在代码中添加以下
using
指令:using Proxoft.WinForms;
- 您就可以开始使用了。下面的代码片段展示了如何将
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 日 - 初始文章发布