出于通常的原因,我需要在应用程序中使用一些常量。
我考虑过的方法:
1)声明一个Enum:public enum myOptions
{
MyOption1 = 72,
MyOption2 = 31,
MyOption3 = 44
}
虽然这是很好的编程,我可以将枚举直接绑定到DDL,但是枚举"名称"在用户看到它们时是丑陋的-用户将看到"MyOption1",而我希望他们看到"MyOption #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,在那里我可以有一个漂亮的显示名?现在我唯一能想到的是同时构建Enum和List,这看起来很烦人。
我总是倾向于使用装饰的枚举值:
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;
}
根据@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的当前值匹配的项。
欢迎对我的实现提出评论和批评(实际上,我很感激-就像我说的,我正在努力学习…)
还有什么建议吗?
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();