枚举的显示和绑定
1.定义一个存储枚举的显示名称的定制特性:
/// <summary>
/// 枚举的显示名称
/// </summary>
[global::System.AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
public sealed class EnumShowNameAttribute : Attribute
{
/// <summary>
/// 显示名称
/// </summary>
public string ShowName { get; private set; }
/// <summary>
/// 构造枚举的显示名称
/// </summary>
/// <param name="showName">显示名称</param>
public EnumShowNameAttribute(string showName)
{
this.ShowName = showName;
}
}
2.为每个枚举的成员添加此定制特性。如:
/// <summary>
/// 性别
/// </summary>
public enum Sex
{
/// <summary>
/// 男
/// </summary>
[EnumShowName("男")]
Man=0,
/// <summary>
/// 女
/// </summary>
[EnumShowName("女")]
Woman=1,
}
3.写显示枚举名称、绑定控件的扩展方法。
显示枚举名称方法(ToShowName())的思路本来很简单:根据枚举值获取其EnumShowNameAttribute定制特性的ShowName属性值。但我这里的代码并不少,主要用来处理以下几点:
1.缓存。由于用反射的方式获取值性能不好。于是这里用了一个Dictionary<string,string>来缓存枚举值对应的ShowName,Key是[枚举类的FullName].[枚举值的ToString],Value是ShowName值。那么只是第一次访问的时候需要反射,以后都从缓存里取就行了。
2.FlagsAttribute标记的枚举。此标志表示这个枚举按位排列。那么不缓存它,且需要拿输入值与枚举的成员一个一个比较。
另:绑定的时候应尊重控件的AppendDataBoundItems属性,给使用时更多选择。
static private Dictionary<string, string> _cacheEnumShowNamedDic = new Dictionary<string, string>();
/// <summary>
/// 输出枚举的ShowName,需要枚举声明EnumShowNameAttribute
/// </summary>
/// <param name="en">待输出的枚举</param>
/// <returns></returns>
static public string ToShowName(this Enum en)
{
return ToShowName(en, false, ",");
}
/// <summary>
/// 输出枚举的ShowName,需要枚举声明EnumShowNameAttribute
/// </summary>
/// <param name="en">待输出的枚举</param>
/// <param name="exceptionIfNotSuccess">未成功是否抛出异常</param>
/// <param name="flagsSeparator">Flags类型输出时的间隔符</param>
/// <returns></returns>
static public string ToShowName(this Enum en, bool exceptionIfFail,string flagsSeparator)
{
string showName;
string enFullName = GetEnumFullName(en);
// 先在缓存中找
if (!_cacheEnumShowNamedDic.TryGetValue(enFullName, out showName))
{
// 获取枚举类型
Type enumType = en.GetType();
// 查看其是否Flags
object[] flagsAtts = enumType.GetCustomAttributes(typeof(FlagsAttribute), false);
// 有Flags,按位处理,不缓存
if (flagsAtts != null && flagsAtts.Length > 0)
{
long currentVal = Convert.ToInt64(en);
StringBuilder sb = new StringBuilder();
string[] names = Enum.GetNames(enumType);
string zeroString = "";
foreach (string name in names)
{
long val = Convert.ToInt64(Enum.Parse(enumType, name));
// val为0,则跳过
if (val == 0)
{
object[] atts = enumType.GetField(name).GetCustomAttributes(typeof(EnumShowNameAttribute), false);
if (atts.Length > 0)
{
// 找到,设置
zeroString = ((EnumShowNameAttribute)atts[0]).ShowName;
}
continue;
}
// 比较
if ((val & currentVal) == val)
{
// 加间隔符
if (sb.Length != 0)
{
sb.Append(flagsSeparator);
}
// 加上定制特性值
object[] atts = enumType.GetField(name).GetCustomAttributes(typeof(EnumShowNameAttribute), false);
if (atts.Length > 0)
{
// 找到,设置
sb.Append(((EnumShowNameAttribute)atts[0]).ShowName);
}
else
{
// 没找到定制特性,参数指定抛出异常则抛出异常
if (exceptionIfFail)
{
throw new InvalidOperationException(string.Format("此枚举{0}未定义EnumShowNameAttribute", enFullName));
}
sb.Append(name);
}
}
}
// 输出
if (sb.Length > 0)
{
return sb.ToString();
}
return zeroString;
}
// 无Flags
else
{
// 找字段
FieldInfo fieldInfo = enumType.GetField(en.ToString());
if (fieldInfo == null)
{
throw new InvalidOperationException(string.Format("非完整枚举{0}", enFullName));
}
// 找定制特性
object[] atts = fieldInfo.GetCustomAttributes(typeof(EnumShowNameAttribute), false);
if (atts.Length > 0)
{
// 找到,设置
showName = ((EnumShowNameAttribute)atts[0]).ShowName;
lock (_cacheEnumShowNamedDic)
{
_cacheEnumShowNamedDic[enFullName] = showName;
}
}
else
{
// 没找到定制特性,参数指定抛出异常则抛出异常
if (exceptionIfFail)
{
throw new InvalidOperationException(string.Format("此枚举{0}未定义EnumShowNameAttribute", enFullName));
}
// 否则直接输出本身的ToString
return en.ToString();
}
}
}
return showName;
}
/// <summary>
/// 获取枚举的全名
/// </summary>
/// <param name="en"></param>
/// <returns></returns>
static private string GetEnumFullName(Enum en)
{
return en.GetType().FullName + "." + en.ToString();
}
/// <summary>
/// 给ListControl绑定枚举值
/// </summary>
/// <typeparam name="T">枚举类型</typeparam>
/// <param name="listControl">待绑定的控件</param>
static public void BindEnum<T>(this System.Web.UI.WebControls.ListControl listControl)
where T : struct
{
// 获取类型
Type type = typeof(T);
if (!type.IsEnum)
{
throw new InvalidOperationException("类型必须是枚举:" + type.FullName);
}
// 获取枚举成员
Array values = Enum.GetValues(type);
// 绑定值
if (!listControl.AppendDataBoundItems)
{
listControl.Items.Clear();
}
foreach (Enum item in values)
{
listControl.Items.Add(new System.Web.UI.WebControls.ListItem(item.ToShowName(), item.ToString()));
}
}
4.使用。直接在枚举上ToShowName就可以得到显示的名称,在ListControl(DropDownList继承此类)用BindEnum方法绑定枚举。如:
string str = Sex.Man.ToShowName();
注:有多语言需求的项目和大项目,不推荐使用这种方案,而建议将显示的文字存储在单独的文件中。
参阅:http://www.cnblogs.com/zhucai/archive/2009/05/27/enum_bind.html
http://www.cnblogs.com/JeffreyZhao/archive/2009/01/07/AttachDataExtensions.html