ASP.NET MVC的Model元数据与Model模板:将”ListControl”引入AS
我们不仅可以创建相应的模板来根据Model元数据控制种类型的数据在UI界面上的呈现方法,还可以通过一些扩展来控制Model元数据本身。在某些情况下通过这两者的结合往往可以解决很多特殊数据的呈现问题,我们接下来演示的实例就是典型的例子。[本文已经同步到《How ASP.NET MVC Works?》中] 传统的ASP.NET具有一组重要的控件类型叫做列表控件(ListControl),它的子类包括DropDownList、ListBox、RadioButtonList和CheckBoxList等。对于ASP.NET MVC来说,我们可以通过HtmlHelper/HtmlHelper<TModel>的扩展方法DropDownList/DropDownListFor和ListBox/ListBox在界面上呈现一个下拉框和列表框,但是我们需要手工指定包含的所有列表选项。在一般的Web应用中,尤其是企业应用中,我们会选择将这些列表进行单独地维护,如果我们在构建“列表控件”的时候能够免去手工提供列表的工作,这无疑会为开发带来极大的遍历,而这实际上很容易实现。[源代码从这里下载] 一、实现的效果我们先来看看通过该扩展最终实现的效果。在通过Visual Studio的ASP.NET MVC项目模板创建的空Web应用中,我们定义一个作为Model表示员工的Employee类型。如下面的代码片断所示,表示性别、学历、部门和技能的属性分别应用了RadioButtonListAttribute、DropdownListAttribute、ListBoxAttribute和CheckBoxListAttribubte四个特性。从名称可以看出来,这四个特性分别代表了目标元素呈现在UI界面上的形式,即对应着传统ASP.NET Web应用中的四种类型的列表控件:RadioButtonList、DropdownList、ListBox和CheckBoxList。特性中指定的字符串表示预定义列表的名称。 1: public class Employee 3: [DisplayName("姓名")]
5:? 7: [DisplayName("性别")]
9:? 11: [DisplayName("学历")]
13:? 15: [DisplayName("所在部门")]
17:? 19: [DisplayName("擅长技能")]
21: } 在创建的默认HomeController中,我们定义了如下一个Index操作方法。在该方法中,我们创建了一个具体的Employee对象并对它的所有属性进行了相应设置,最终将该对象呈现在默认的View中。 3: public ActionResult Index()
5: Employee employee = new Employee
7: Name = "张三",
9: Education = 10: Departments= new string[] { "HR","AD" },1)" id="lnum11"> 11: Skills = "CSharp",1)">"AdoNet" } 13: return View(employee);
15: } 如下所示的是上面的Index操作对应的View定义,这是一个以Model类型为Employee的强类型View,我们通过调用HtmlHelper<TModel>的模板方法EditorFor将作为Model的Employee对象的所有属性以编辑模式呈现出来。 2: <table>
4: td>@Html.LabelFor(m => m.Name)</><>@Html.EditorFor(m = 5: 6: 7: > m.Gender) 9: 10: > m.Education) 11: 12: > m.Departments) 14: 15: 16: > m.Skills) 17: > class ListItem string Value { get; set; } interface IListProvider 4: } 6: { static DefaultListProvider() 10: var items = new ListItem[]{
13: listItems.Add("Gender",items);
15: items = new ListItem[]{
20: listItems.Add("Education",items);
22: items = new ListItem[]{
26: listItems.Add("Department",1)" id="lnum27"> 27:?
32: listItems.Add("Skill",1)" id="lnum33"> 33: }
35: { 37: if (listItems.TryGetValue(listName,1)">out items))
39: return items;
41: return new ListItem[0]; 43: } 接下来我们定义如下一个ListProviders类型,它的静态只读属性Current表示当前的ListProvider,而对当前ListProvider的注册通过静态方法SetListProvider来实现。如果没有对当前ListProvider进行显式注册,则默认采用DefaultListProvider。 static IListProvider Current { get; private set; }
5: { 7: } 10: Current = providerAccessor(); 12: } 三、通过对HtmlHelper/HtmlHelper<TModel>的扩展生成“ListControl”的HTML基于四种“列表控件”的HTML生成是通过定义HtmlHelper的扩展方法来实现的,如下面的代码所示,定义在ListControlExtensions中的四个扩展方法实现了针对这四种列表控件的UI呈现。参数listName表示使用的预定义列表的名称,而value和values则表示绑定的值。RadioButtonList/DropdownList只允许单项选择,而ListBox/CheckBoxList允许多项选择,所以对应的值类型分别是string和IEnumerable<string>。 //其他成员
6: return RadioButtonCheckBoxList(htmlHelper,listName,item =>
8: } 11: { 13: } 16: { 18: List<SelectListItem> selectListItems = new List<SelectListItem>();
20: { 24: } 26: } 30: var listItems = ListProviders.Current.GetListItems(listName); 32: in listItems)
34: selectListItems.Add( 35: Text = item.Text,Selected = value == item.Value}); return htmlHelper.DropDownList(name,1)" id="lnum38"> 38: } static MvcHtmlString CheckBoxWithValue(bool isChecked,1)">value)
6: ModelState modelState; 8: //将ModelState设置为表示是否勾选布尔值
10: { 12: } 14: try
16: html = htmlHelper.CheckBox(name,isChecked); finally 20: //将ModelState还原
22: { 24: } 26: string htmlString = html.ToHtmlString();
); new MvcHtmlString(element.ToString()); 33:? 36: var listItems = ListProviders.Current.GetListItems(listName); 38: TagBuilder tr = "tr");
41: TagBuilder td = "td");
43: td.InnerHtml += listItem.Text; 45: } 47: new MvcHtmlString(table.ToString());
49: } 方法RadioButtonCheckBoxList在生成RadioButtonList和CheckBoxList的时候才用<table>进行布局。组成RadioButtonList的单个RadioButton最终是调用HtmlHelper现有的扩展方法RadioButton生成的,而CheckBoxList中的CheckBox则是通过调用我们自定义的CheckBoxWithValue方法生成的。CheckBoxWithValue最终还是调用HtmlHelper现有的扩展方法CheckBox生成单个CheckBox对应的HTML,但是方法值支持布尔值的绑定,并且会生成一个在这里不需要的Hidden元素,所以我们不得不在调用该方法的前后作一些手脚。 四、ListAttribute现在我们来介绍应用在Employee属性上的四个特性的定义。如下面的代码片断所示,基于四种“列表控件”的特性均继承自抽象特性ListAttribute。ListAttribute实现了IMetadataAware接口,在实现的OnMetadataCreated方法中将在构造函数中指定的代表列表名称的ListName属性添加到表示Model元数据的ModelMetadata对象的AdditionalValues属性中。四个具体的列表特性重写了OnMetadataCreated方法,并在此基础上将ModelMetadata的TemplateHint分别设置为DropdownList、ListBox、RadioButtonList和CheckBoxList。 abstract class ListAttribute : Attribute,IMetadataAware
string ListName { get; private set; }
6: { 8: } 10: { 12: } 15: [AttributeUsage(AttributeTargets.Property)] 17: { 20: { } base.OnMetadataCreated(metadata); 25: } 28: [AttributeUsage(AttributeTargets.Property)] 30: { 33: { } 36: base.OnMetadataCreated(metadata);
39: } 41: [AttributeUsage(AttributeTargets.Property)] 43: { 47:? 50: 51: metadata.TemplateHint = "RadioButtonList"; 53: } 55: [AttributeUsage(AttributeTargets.Property)] 57: { 61:? 64: 65: metadata.TemplateHint = "CheckBoxList"; 67: } 五、模板View的定义由于四个具体的ListAttribute已经对表示模板名称的ModelMetadata的TemplateHint进行了设置,那么我们针对它们定义相应的分部View作为对应的模板,那么在调用HtmlHelper/HtmlHelper<TModel>相应模板方法的时候就会按照这些模板对目标元素进行呈现。实现如上图所示的效果的四个模板定义如下,它们被保存在ViewSharedEditorTemplates目录下面。 2: @model string
4: string listName = (string)ViewData.ModelMetadata.AdditionalValues["ListName"]; 6: } 9: @model IEnumerablestring 10: @{ 12: @Html.ListBox("",Model) 16: @model string 18: string listName = (string)ViewData.ModelMetadata.AdditionalValues["ListName"]; 22: CheckBoxList.cshtml: 25: string listName = (string)ViewData.ModelMetadata.AdditionalValues["ListName"]; 27: } ? ASP.NET MVC的Model元数据与Model模板:预定义模板
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- asp.net-mvc – 使用Razor DropDownList的Bootstrap
- asp.net-mvc – 单个控制器站点的ASP.NET MVC路由
- asp.net-mvc – RenderAction调用错误的动作方法
- asp.net – Dotnetopenauth oAuth服务提供商的解释
- asp.net – 您如何看待Postgres和Firebird数据库?
- asp.net – 如何从服务器控件中删除’name’属性?
- asp.net-mvc – 如何使用表单身份验证提供保持登录功能?
- asp.net – HTML敏捷包删除break标签关闭
- asp.net-core – 使用asp.net核心发布视图
- asp.net – Umbraco CMS(.NET):加载xslt /用户控件的日志错