在建设网站当中,生成下拉框本来是一件非常微不足道的事,但是在实际应用当中,我常常会碰到这样的一个场景:刚开始设计时仅固定为几个下拉选项,但是经过几次迭代和需求更改之后,这个下拉选项会不断地被要求改来改去。
当然,我们希望这个下拉框是动态读取数据库中的数据,并实现动态的后台可视化管理,但有些场景下并不会提供一张表数据。
所以在一次开发中,我突然冒出一个想法。借用类似Dictionary的键值映射关系,因为下拉框元素也刚好可以看成这样的键-值对的形式。
所以我自定义了一个映射的类如下:
<span style="font-family:Courier New;">public class MapEntity
{
#region 属性
/// <summary>
/// 键
/// </summary>
public long Key { set; get; }
/// <summary>
/// 值
/// </summary>
public string Value { get; set; }
/// <summary>
/// 是否启用
/// </summary>
public bool Enable { get; set; }
#endregion
#region 构造方法
/// <summary>
/// 默认
/// </summary>
public MapEntity() { }
/// <summary>
/// 构造函数
/// </summary>
/// <param name="key">主键</param>
/// <param name="value">值</param>
/// <param name="enable">是否启用标志, 默认启用</param>
public MapEntity(long key, string value, bool enable = true)
{
this.Key = key;
this.Value = value;
}
#endregion
}</span>
因为在这种景中,所的供的下拉选项仅仅是几种状态或是各种选项,这个状态选项又是跟其它的业务相关联的,故定义一个枚举,示例如下:
<span style="font-family:Courier New;">public enum ActiveStatusEnum : int
{
/// <summary>
/// 未审核
/// </summary>
[Description("未审核")]
UnAudit = 1,
/// <summary>
/// 等待
/// </summary>
[Description("等待")]
Wait = 2,
/// <summary>
/// 就绪
/// </summary>
[Description("就绪")]
Ready = 3,
/// <summary>
/// 开始
/// </summary>
[Description("开始")]
Start = 4,
/// <summary>
/// 完成
/// </summary>
[Description("完成")]
Finish = 5,
/// <summary>
/// 停止
/// </summary>
[Description("停止")]
Stop = -1
}</span>
然后写一个辅助类,封装 方法:
<span style="font-family:Courier New;">public class MapHelper
{
public static MapEntity[] WorkList = new MapEntity[] {
new MapEntity( (int)ActiveStatusEnum.UnAudit, "未审核" ),
new MapEntity( (int)ActiveStatusEnum.Wait, "等待" ),
new MapEntity( (int)ActiveStatusEnum.Ready, "准备" ),
new MapEntity( (int)ActiveStatusEnum.Start, "开始" ),
new MapEntity( (int)ActiveStatusEnum.Finish, "完成" ),
new MapEntity( (int)ActiveStatusEnum.Stop, "终止", false),
};
#region 生成下拉框元素集合
/// <summary>
/// 生成下拉框元素集合
/// </summary>
/// <param name="fillArray"></param>
/// <param name="pId"></param>
/// <param name="IsNeedAll"></param>
/// <returns></returns>
public static List<SelectListItem> GetDropDownList(MapEntity[] fillArray, long pId, bool IsNeedAll = false )
{
List<SelectListItem> ReturnObj = new List<SelectListItem>();
if (pId == Int32.MinValue) //如果等于最小值,则直接返回
{
return ReturnObj;
}
foreach (var item in fillArray) //遍历数组元素生成下拉框
{
SelectListItem ItemObj = new SelectListItem();
ItemObj.Text = item.Value;
ItemObj.Value = item.Key.ToString();
ItemObj.Selected = item.Key == pId;
ReturnObj.Add(ItemObj);
}
if (IsNeedAll) //是否需要插入全部选项
{
SelectListItem ItemObj = new SelectListItem();
ItemObj.Text = "全部";
ItemObj.Value = "-1";
ItemObj.Selected = pId == -1;
ReturnObj.Add(ItemObj);
}
return ReturnObj;
}
#endregion
#region 通过
/// <summary>
/// 通过键 获取映射值
/// </summary>
/// <param name="fillArray">集合对象</param>
/// <param name="key">指定键</param>
/// <param name="IsIgnoreEnable">是否忽略"是否启用"选项,默认否</param>
/// <returns></returns>
public static string GetMappingValueByKey(MapEntity[] fillArray, long key, bool IsIgnoreEnable = false)
{
foreach (var item in fillArray)
{
if (item.Key == key)
{
if ( ( !IsIgnoreEnable && item.Enable ) || IsIgnoreEnable )
{
return item.Value;
}
}
}
return string.Empty;
}
/// <summary>
/// 通过键 获取映射值
/// </summary>
/// <param name="fillArray">集合对象</param>
/// <param name="Value">值</param>
/// <param name="IsIgnoreEnable">是否忽略"是否启用"选项,默认否</param>
/// <param name="IsIgnoreCase">是否忽略大小写,默认否</param>
/// <returns>如果集合中的键存在-999,则不适合此方法</returns>
public static long GetMappingKeyByValue(MapEntity[] fillArray, string Value, bool IsIgnoreCase = false, bool IsIgnoreEnable = false)
{
if (string.IsNullOrEmpty(Value))
{
return -999;
}
foreach (var item in fillArray)
{
if (IsIgnoreCase)
{
//忽略大小写
if (item.Value.ToLower().Equals(Value.ToLower()))
{
if ((!IsIgnoreEnable && item.Enable) || IsIgnoreEnable)
{
return item.Key;
}
}
}
else
{
//不忽略大小写
if (item.Value.Equals(Value))
{
if ((!IsIgnoreEnable && item.Enable) || IsIgnoreEnable)
{
return item.Key;
}
}
}
}
return -999;
}
#endregion
}</span>
最后调用时,如下:
<span style="font-family:Courier New;"> public class HomeController : Controller
{
//
// GET: /Home/
public ActionResult Index()
{
ViewData["DDList"] = MapHelper.GetDropDownList(
MapHelper.WorkList, (int)ActiveStatusEnum.UnAudit);
return View();
}
}</span>
所以在下次进行变更的时候,只需要设置Enabled属性,可以设置启用或者不启用,也可以随时添加新的选项。这样非常的灵活方便。
当然,这里其实可以有另外的一种方法,那就是通过反射机制。代码如下:
<span style="font-family:Courier New;"> /// <summary>
///
/// </summary>
/// <param name="EnumType">枚举对象的类型</param>
/// <param name="pId">指定的枚举名称</param>
/// <param name="IsNeedAll">是否需要添加全部选项</param>
/// <returns></returns>
public static List<SelectListItem> GetDropDownList(Type EnumType, string pId, bool IsNeedAll = false)
{
List<SelectListItem> ResultObj = new List<SelectListItem>();
//获取当前对象类型的所有成员
MemberInfo[] MemberArray = EnumType.GetMembers()
.Where(s => s.MemberType.Equals(MemberTypes.Field) && !s.Name.Equals("value__")).ToArray();
bool IsFind = false;
foreach (var memberItem in MemberArray)
{
//获取当前成员的自定义特性
IEnumerable<CustomAttributeData> CustomArray = memberItem.CustomAttributes;
SelectListItem SelObj = new SelectListItem();
foreach(var customItem in CustomArray)
{
//这里因为只设置了DescriptionAttribute,所以在读取第一条后直接跳出
SelObj.Text = customItem.ConstructorArguments[0].Value.ToString();
break;
}
SelObj.Value = memberItem.Name;
SelObj.Selected = IsFind = memberItem.Name.Equals(pId);
ResultObj.Add(SelObj);
}
if (IsNeedAll)
{
if (IsNeedAll) //是否需要插入全部选项
{
SelectListItem ItemObj = new SelectListItem();
ItemObj.Text = "全部";
ItemObj.Value = "-1";
ItemObj.Selected = !IsFind;
ResultObj.Add(ItemObj);
}
}
return ResultObj;
}</span>
在调用时,只需要传入如下参数示例:
ViewData["DDList2"] = MapHelper.GetDropDownList(typeof(ActiveStatusEnum), ActiveStatusEnum.UnAudit.ToString());
虽然反射机制也是可以实现,但是却少了一些控制上的灵活性以及多了一些性能上的损耗,相比之下,自定义的映射类,可以自定义属性控制开关,添加额外的信息等等。
这只是在写代码过程中一些小的思考,希望自己能有更多的这样的思考,积少成多!加油!