在做web项目的时候经常使用CheckBoxList,RadioButtonList,DropDownList控件,对于这些控件的数据源如果需要客户动态维护的一般存于数据库中,但是大量的这些控件的数据源并不需要提供可视化的动态维护,如果直接在页面中写死则会存在重用性不强,后台代码编写容易出错等问题。现在我整理成使用枚举实现,重用性好,编写代码使用枚举值比较,不容易出错,虽然通过反射实现,性能并不是最好,但是个人觉得牺牲这么一点点性能还是值得的。具体代码分析如下:
首先是枚举的定义,这里定义了国家类型的枚举
/// 国家
/// </summary>
public enum Country
{
[ListItemText("中国")]
China = 1,
[ListItemText(
"美国")]America = 2,
[ListItemText(
"德国")]Germany = 3,
[ListItemText(
"英国")]England = 4,
[ListItemText(
"法国")]France = 5,
[ListItemText(
"日本")]Japan = 6
}
该枚举中的枚举值,即1,2,3,4,5,6对应于CheckBoxList,RadioButtonList,DropDownList中的ListItem的value,即值。
枚举中的特性 ListItemText 对应于ListItem中的text。
输出到客户端的html如下(DropDownList示例)
<option selected="selected" value="1">中国</option>
<option value="2">美国</option>
<option value="3">德国</option>
<option value="4">英国</option>
<option value="5">法国</option>
<option value="6">日本</option>
</select>
定义继承自DropDownList的自定义控件,用于实现该枚举类型和DropDownList的整合。
{
/// <summary>
/// 在页面中设置该控件的枚举类型名称,必须设置
/// </summary>
public string EnumTypeName { get; set; }
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (Page.IsPostBack) return;
var a
= Assembly.Load("WebApplication");if (string.IsNullOrEmpty(EnumTypeName))
throw new Exception("必须设置属性EnumTypeName的值");
var t
= a.GetType(EnumTypeName);var list = Util.GetListItemFromEnum<int>(t);
foreach (ListItem li in list)
{
this.Items.Add(li);
}
}
}
该类只需要设置一个属性EnumTypeName 即枚举的具体类型就可以(类型为全名,需要包含命名空间)
在页面中使用该控件设置EnumTypeName 属性值:
</cc1:EnumSelect>
编译完之后可以从工具箱的自定义组件中拖拉到页面中
EnumSelect1类中的Util类如下:
{
/// <summary>
/// 根据一个枚举类型转化成ListItemCollection
/// </summary>
/// <param name="enumType">枚举类型</param>
/// <returns></returns>
public static ListItemCollection GetListItemFromEnum<T>(Type enumType)
{
var list = new ListItemCollection();
if (enumType.IsEnum != true){
throw new Exception("方法GetListItemFromEnum只能接受枚举类型");
}
var typeText
= typeof(ListItemTextAttribute);//获得枚举的字段信息(因为枚举的值实际上是一个static的字段的值)
var fields = enumType.GetFields();
foreach (var fi in fields)
{
if (!fi.FieldType.IsEnum) continue;
//获得这个字段的所有自定义特性,这里只查找ListItemTextAttribute特性
var arr = (ListItemTextAttribute[])(fi.GetCustomAttributes(typeof(ListItemTextAttribute), true));
if (arr.Length <= 0) continue;
var li
= new ListItem{
Value =
Convert.ChangeType(
enumType.InvokeMember(fi.Name, BindingFlags.GetField, null, null, null),
typeof (T)).ToString()
};
//因为ListItemTextAttribute这个自定义特性是不允许重复的,所以我们只取第一个就可以了!
var a = (ListItemTextAttribute)arr[0];
//获得特性的描述值,也就是‘男’‘女’等中文描述
li.Text = a.Text;
list.Add(li);
}
return list;
}
/// <summary>
/// 根据枚举值获得指定的ListItemTextAttribute的值
/// </summary>
/// <typeparam name="T">必须为枚举类型</typeparam>
/// <param name="e"></param>
/// <returns></returns>
public static string GetEnumListItemText<T>(T e)
{
var t = typeof(T);
if (!t.IsEnum)
{
throw new Exception("泛型参数必须为枚举类型");
}
var mis
= t.GetMember(e.ToString());if (mis.Length != 1)
{
throw new Exception("无法找到该枚举属性或者该枚举属性数量大于1");
}
var arr
= (ListItemTextAttribute[])mis[0].GetCustomAttributes(typeof(ListItemTextAttribute), false);if (arr.Length == 0)
{
throw new Exception("未指定该枚举属性的Text值");
}
return arr[0].Text;
}
}
Util类有两个方法:
1.GetListItemFromEnum方法: 传入一个具体的枚举类型,返回 CheckBoxList,RadioButtonList,DropDownList控件需要的数据源ListItemCollection。
2.GetEnumListItemText方法: 传入一个枚举值,比如Country.China,返回的是具体的text,这里返回 “中国”。
如果是根据具体的选中项来取得文本值,则代码如下
if (!string.IsNullOrEmpty(EnumRadioButtonList1.SelectedValue))
province = Util.GetEnumListItemText<Province>((Province)(int.Parse(EnumRadioButtonList1.SelectedValue)));
最后还有一个重要的特性类没有介绍,具体代码如下:
/// 枚举类型的字段 ListItem Text 特性
/// </summary>
[AttributeUsage(AttributeTargets.Field)]
public class ListItemTextAttribute : Attribute
{
public ListItemTextAttribute(string text)
{
this.Text = text;
}
public string Text { get; set; }
}
在可以下载的代码包中我已经分别实现了 CheckBoxList,RadioButtonList,DropDownList控件和枚举的整合自定义控件。
分别是 EnumCheckBoxList,EnumRadioButtonList,EnumSelect
Demo界面
在可下载的代码包中对这三个控件都有demo演示的,可以直接运行,VS2008编写
以下是全部代码,可以直接下载
/Files/szp1118/WebApplication.rar