本篇将通过3种方式,把枚举项上的自定义属性填充到下拉框:
1、通过控制器返回List<SelectListItem>类型给前台视图
2、通过为枚举类型属性打上UIHint属性让模版显示枚举项
3、通过自定义元数据提供器DataAnnotationsModelMetadataProvider让模版显示枚举项
我们经常会把类型为Int16的属性通过枚举来获得。比如:
public class SomeClass { public int16 Status{get;set;} }
对应的枚举:
public enum StatusEnum
{Enable = 0,
Disable = 1
}
在MVC视图中可能会这样写:
<select id="sel"><option value="">==选择状态==</option>
<option value="0">启用</option>
<option value="1">禁用</option>
</select>
如果枚举的项发生变化怎么办?比如:
public enum StatusEnum
{Enable = 0,
Disable = 1,
NeverComeback = 2
}
如果修改每一页的代码,显然是不合理的。最理想的做法是:为每一个枚举项打上属性,显示的时候直接读取枚举以及枚举项属性值。
通过控制器返回List<SelectListItem>类型给前台视图
定义一个Model,其中有一个类型为Int16的属性Status,这个属性用来接收枚举值。
using System;using System.ComponentModel.DataAnnotations;namespace MvcApplication1.Models{public class Stadium
{public int Id { get; set; }
[Display(Name = "场馆名称")]public string Name { get; set; }
[Display(Name = "是否启用")] public Int16 Status { get; set; }}
}
为每个枚举项打上的属性需要我们自定义,通过构造函数接收名称,并提供一个属性供外部访问。
using System;namespace MvcApplication1.Extension{public class EnumDisplayNameAttribute : Attribute
{private string _displayName;
public EnumDisplayNameAttribute(string displayName)
{ this._displayName = displayName;}
public string DisplayName
{ get { return _displayName; }}
}
}
为每个枚举项打上自定义属性。
using MvcApplication1.Extension;namespace MvcApplication1.Models.Enum{public enum StatusEnum
{ [EnumDisplayName("启用")]Enable = 0,
[EnumDisplayName("禁用")]Disable = 1
}
}
我们的目的是在控制器获取List<SelectListItem>集合,然后传递到前台视图。现在,枚举和枚举项上的自定义属性都有了,有必要创建一个帮助类来帮我们获取List<SelectListItem>集合。
using System;using System.Collections.Generic;using System.Reflection;using System.Web.Mvc;namespace MvcApplication1.Extension{public class EnumExt
{ /// <summary> /// 根据枚举成员获取自定义属性EnumDisplayNameAttribute的属性DisplayName /// </summary> /// <param name="e"></param> /// <returns></returns>public static string GetEnumCustomDescription(object e)
{ //获取枚举的Type类型对象Type t = e.GetType();
//获取枚举的所有字段FieldInfo[] ms = t.GetFields();
//遍历所有枚举的所有字段foreach (FieldInfo f in ms)
{ if (f.Name != e.ToString()) { continue;}
//第二个参数true表示查找EnumDisplayNameAttribute的继承链if (f.IsDefined(typeof (EnumDisplayNameAttribute), true))
{ return(f.GetCustomAttributes(typeof(EnumDisplayNameAttribute), true)[0] as EnumDisplayNameAttribute)
.DisplayName;
}
}
//如果没有找到自定义属性,直接返回属性项的名称 return e.ToString();}
/// <summary> /// 根据枚举,把枚举自定义特性EnumDisplayNameAttribut的Display属性值撞到SelectListItem中 /// </summary> /// <param name="enumType">枚举</param> /// <returns></returns>public static List<SelectListItem> GetSelectList(Type enumType)
{ List<SelectListItem> selectList = new List<SelectListItem>();foreach (object e in Enum.GetValues(enumType))
{selectList.Add(new SelectListItem(){Text = GetEnumCustomDescription(e),Value = ((int)e).ToString()});
}
return selectList;}
}
}
在控制器中,通过ViewData把List<SelectListItem>集合往前台传。控制器包含2个方法,一个方法用来显示创建视图界面,另一个用来显示编辑视图界面。
//创建 public ActionResult Index() {ViewData["s"] = EnumExt.GetSelectList(typeof (StatusEnum));
return View(new Stadium());
}
//编辑 public ActionResult Edit() { Stadium s = new Stadium() {Id = 2,
Name = "水立方", Status = (short)StatusEnum.Disable};
ViewData["s"] = EnumExt.GetSelectList(typeof(StatusEnum));
return View(s);}
在强类型的创建视图界面中,通过@Html.DropDownListFor(model => model.Status,(List<SelectListItem>)ViewData["s"])接收来自控制器的数据。
@model MvcApplication1.Models.Stadium
@{ ViewBag.Title = "Index"; Layout = "~/Views/Shared/_Layout.cshtml";}
<h2>Index</h2>
@using (Html.BeginForm()) { @Html.ValidationSummary(true)<fieldset>
<legend>Stadium</legend>
<div class="editor-label">
@Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Name)
@Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Status)
</div>
<div class="editor-field">
@Html.DropDownListFor(model => model.Status,(List<SelectListItem>)ViewData["s"])@Html.ValidationMessageFor(model => model.Status)
</div>
<p>
<input type="submit" value="添加" />
</p>
</fieldset>
}
@section Scripts { @Scripts.Render("~/bundles/jqueryval")}
在强类型的编辑视图界面中,同样通过@Html.DropDownListFor(model => model.Status,(List<SelectListItem>)ViewData["s"])接收来自控制器的数据。
@model MvcApplication1.Models.Stadium
@{ ViewBag.Title = "Edit"; Layout = "~/Views/Shared/_Layout.cshtml";}
<h2>Edit</h2>
@using (Html.BeginForm()) { @Html.ValidationSummary(true)<fieldset>
<legend>Stadium</legend>
@Html.HiddenFor(model => model.Id)
<div class="editor-label">
@Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Name)
@Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Status)
</div>
<div class="editor-field">
@Html.DropDownListFor(model => model.Status,(List<SelectListItem>)ViewData["s"])@Html.ValidationMessageFor(model => model.Status)
</div>
<p>
<input type="submit" value="编辑" />
</p>
</fieldset>
}
@section Scripts { @Scripts.Render("~/bundles/jqueryval")}
通过为枚举类型属性打上UIHint属性让模版显示枚举项
由于模版是根据属性类型来判断的,再定义一个Model,其中一个属性类型是枚举。
using System.ComponentModel.DataAnnotations;using MvcApplication1.Models.Enum;namespace MvcApplication1.Models{public class Stadium1
{public int Id { get; set; }
[Display(Name = "场馆名称")]public string Name { get; set; }
[Display(Name = "是否启用")] public StatusEnum Status { get; set; } }
}
在Views/Shared/EditorTemplates文件夹下创建Enum.cshtml,用来处理类型为Enum的属性。
@using System.ComponentModel.DataAnnotations@using System.Reflection@using MvcApplication1.Extension@{ var selectList = new List<SelectListItem>();string optionLabel = null;
object htmlAttributes = null;
var enumType = (Type)Model.GetType();
foreach (var value in Enum.GetValues(enumType))
{ var field = enumType.GetField(value.ToString());var option = new SelectListItem() {Value = value.ToString()};
var display = field.GetCustomAttributes(typeof (EnumDisplayNameAttribute), false).FirstOrDefault() as EnumDisplayNameAttribute;
if (display != null)
{option.Text = display.DisplayName;
}
else { option.Text = value.ToString();}
option.Selected = object.Equals(value, Model);
selectList.Add(option);
}
}
@Html.DropDownList("",selectList, optionLabel, htmlAttributes)
控制器中有2个方法用来显示创建和编辑视图界面。
//创建 public ActionResult TemplateCreate() {return View(new Stadium1());
}
//编辑 public ActionResult TemplateEdit() { Stadium1 s = new Stadium1() {Id = 2,
Name = "水立方",Status = StatusEnum.Disable
};
return View(s);}
强类型的创建视图界面:
@model MvcApplication1.Models.Stadium1
@{ ViewBag.Title = "TemplateCreate"; Layout = "~/Views/Shared/_Layout.cshtml";}
<h2>TemplateCreate</h2>
@using (Html.BeginForm()) { @Html.ValidationSummary(true)<fieldset>
<legend>Stadium</legend>
<div class="editor-label">
@Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Name)
@Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Status)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Status)
@Html.ValidationMessageFor(model => model.Status)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
@section Scripts { @Scripts.Render("~/bundles/jqueryval")}
强类型的编辑视图界面:
@model MvcApplication1.Models.Stadium1
@{ ViewBag.Title = "TemplateEdit"; Layout = "~/Views/Shared/_Layout.cshtml";}
<h2>TemplateEdit</h2>
@using (Html.BeginForm()) { @Html.ValidationSummary(true)<fieldset>
<legend>Stadium</legend>
@Html.HiddenFor(model => model.Id)
<div class="editor-label">
@Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Name)
@Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Status)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Status)
@Html.ValidationMessageFor(model => model.Status)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
@section Scripts { @Scripts.Render("~/bundles/jqueryval")}
最后,给Stadium1的枚举属性,打上UIHint属性,指明使用公共Enum类型模版Views/Shared/EditorTemplates/Enum.cshtml。
using System.ComponentModel.DataAnnotations;using MvcApplication1.Models.Enum;namespace MvcApplication1.Models{public class Stadium1
{public int Id { get; set; }
[Display(Name = "场馆名称")]public string Name { get; set; }
[Display(Name = "是否启用")] [UIHint("Enum")] public StatusEnum Status { get; set; } }
}
通过自定义元数据提供器DataAnnotationsModelMetadataProvider让模版显示枚举项
如果觉得为属性打上[UIHint("Enum")]属性麻烦的话,还可以通过数据提供器,为所有类型为Enum的属性指明模版。
当然自定义的元数据提供器是需要在全局中注册的。
public class MvcApplication : System.Web.HttpApplication
{protected void Application_Start()
{AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
//注册自定义元数据提供其 ModelMetadataProviders.Current = new CustomMetadataProvider();}
}
现在可以把Stadium的[UIHint("Enum")]注释掉。
总结
如果,我们想在下拉框中显示枚举项,首先给枚举项打上自定义属性,通过反射可以拿到自定义属性的相关属性值。
如果,想在控制器方法中获取List<SelectListItem>集合往前台传,我们可以封装一个方法,根据枚举返回List<SelectListItem>集合;
如果想根据属性的类型显示枚举模版,要么给枚举属性打上[UIHint("Enum")],要么在全局自定义一个DataAnnotationsModelMetadataProvider。
原文:http://www.cnblogs.com/lonelyxmas/p/3659399.html