加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

ASP.NET MVC的Model元数据与Model模板:将”ListControl”引入AS

发布时间:2020-12-16 09:07:17 所属栏目:asp.Net 来源:网络整理
导读:我们不仅可以创建相应的模板来根据Model元数据控制种类型的数据在UI界面上的呈现方法,还可以通过一些扩展来控制Model元数据本身。在某些情况下通过这两者的结合往往可以解决很多特殊数据的呈现问题,我们接下来演示的实例就是典型的例子。[本文已经同步到《

我们不仅可以创建相应的模板来根据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类型。如下面的代码片断所示,表示性别、学历、部门和技能的属性分别应用了RadioButtonListAttributeDropdownListAttributeListBoxAttributeCheckBoxListAttribubte四个特性。从名称可以看出来,这四个特性分别代表了目标元素呈现在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();
);
  29:         XElement element = XElement.Parse(htmlString.Substring(0,index));
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的Model元数据与Model模板:模板的获取与执行策略
ASP.NET MVC的Model元数据与Model模板:将ListControl引入ASP.NET MVC

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读