在众多表单元素中,有一类<select>元素用于绑定一组预定义列表。传统的ASP.NET Web Form中,它对应着一组重要的控件类型,即ListControl,我们经常用到DropDownList, ListBox、CheckBoxList和RadioButtonList都是其子类。ASP.NET MVC通过对HtmlHelper和HtmlHelper<TModel>的扩展实现了对不同类型的<select>元素的绑定,它们以扩展方法的形式定义在SelectExtensions中。当我们在操作这些扩展方法的时候,必须手工地提供以 IEnumerable<SelectListItem>对象表示的列表项。如果我们建立一个独立的组件来维护这些预定的列表,那么我们就可以定义一些更加简单的扩展方法以避免手工地指定列表项。[源代码从这里下载]

一、创建一个独立的列表维护组件

我们将这些绑定在<select>元素中的预定义列表中的元素称为Code。作为简单的演示模拟,我们创建了一个名为CodeManager的组件。我们先来看看用于描述单一Code的CodeDescription类型的定义,如下面的代码所示,CodeDescription具有ID、Code、Description、EffectiveStartDate 和EffectiveEndDate。以表示国家的列表为例,Code代表某个国家的代码(比如CN),Description则是一个可读性的描述(比如China)。EffectiveStartDate 和EffectiveEndDate决定了Code的有效期限,比如一组表示“税率”的列表,在不同的时间范围内可能采用不同的列表。换言之,作为统一类别(通过Category属性表示)的列表中可能具有“多套”,它们可以共享相同的Code,我们通过ID来区分这些具有相同Code的列表项。

   1: public class CodeDescription
   2: {
   3:     public string Id { get; set; }
   4:     public string Code { get; set; }
   5:     public string Description { get; set; }
   6:     public string Category{get;set;}
   7:     public DateTime EffectiveStartDate { get; set; }
   8:     public DateTime EffectiveEndDate { get; set; }
   9:  
  10:     public CodeDescription(string code, string description, string category)
  11:     {
  12:         this.Id = Guid.NewGuid().ToString();
  13:         this.Code = code;
  14:         this.Description = description;
  15:         this.Category = category;
  16:         this.EffectiveStartDate = DateTime.MinValue;
  17:         this.EffectiveEndDate = DateTime.MaxValue;
  18:     }
  19: }

如下所示的CodeCollection 表示一组CodeDescription列表,它直接继承自Collection<CodeDescription>类型。由于CodeDescription具有有效期限的概念,我们需要筛选出当前有效的Code,所以我们定义了如下一个GetEffectiveCodes方法。

   1: public class CodeCollection : Collection<CodeDescription>
   2: {
   3:     public IEnumerable<CodeDescription> GetEffectiveCodes()
   4:     {
   5:         return this.Where(code => code.EffectiveStartDate <= DateTime.Today && code.EffectiveEndDate >= DateTime.Today).ToList();
   6:     }
   7: }

在进行Code绑定的时候,我们都是“类别”为单位的。我们总是获取某一个类别(比如国家、性别、婚姻状况和政治面貌等)的Code列表绑定到界面上。如下所示的CodeManager定义了一个GetCode方法获取指定类别的Code列表。而作为Code存储,我们采用了静态字段的形式,从如下所示的代码可以看出我们实际定义了三类Code,即Gender、MaritalStatus和Country,分别表示性别、婚姻状况和国籍。

   1: public static class CodeManager
   2: {
   3:     private static CodeDescription[] codes = new CodeDescription[]
   4:     {
   5:         new CodeDescription("M","Male","Gender"),
   6:         new CodeDescription("F","Female","Gender"),
   7:         new CodeDescription("S","Single","MaritalStatus"),
   8:         new CodeDescription("M","Married","MaritalStatus"),
   9:         new CodeDescription("CN","China","Country"),
  10:         new CodeDescription("US","Unite States","Country"),
  11:         new CodeDescription("UK","Britain","Country"),
  12:         new CodeDescription("SG","Singapore","Country")
  13:     };
  14:     public static CodeCollection GetCodes(string category)
  15:     {
  16:         CodeCollection codeCollection = new CodeCollection();
  17:         foreach(var code in codes.Where(code=>code.Category == category))
  18:         {
  19:             codeCollection.Add(code);
  20:         }
  21:         return codeCollection;
  22:     }
  23: }

二、定义HtmlHelper的扩展方法实现基于“列表类别”的绑定

现在我们来定义针对HtmlHelper的扩展方法通过从CodeManager获取的Code列表来进行“列表控件”的绑定。表示列表项的SelectListItem具有Text和Value两个属性,分别表示显示的文本和对应的值。在默认的情况下,它们应该对应于CodeDescription的Description和Code,但是有时候却需要进行相应的定制。比如说,有时候我们希望通过CodeDescription的ID来作为SelectListItem的值,或者说通过将SelectListItem显示为Code和Description的组合,比如“CN-China”。为此我们定义了如下一个BindingOption类型。

   1: public class BindingOption
   2: {
   3:     public string OptionalLabel { get;  set; }
   4:     public string TextTemplate { get; set; }
   5:     public string ValueTemplate { get; set; }
   6:  
   7:     public BindingOption()
   8:     {
   9:         this.OptionalLabel = null;
  10:         this.TextTemplate = "{Description}";
  11:         this.ValueTemplate = "{Code}";
  12:     }
  13: }

OptionalLabel表示添加的提示性的文本(比如“请选择一个Xxx”),而TextTemplate 和ValueTemplate 表示最终作为SelectListItem的Text和Value属性的模板,模板中包含相应的站位符({Id}、{Code}和{Description})。

我们为HtmlHelper编写了如下4个扩展方法用于针对DropDownList和ListBox的绑定,在参数中我们无须提供SelectListItem列表,而只需要提供Code和类别即可。而BindingOption 决定了最终作为SelectListItem的Text和Value属性,以及是否需要添加一个提示性的文字和文字内容。在真正的项目中,我们可以将BindingOption的设置定义在配置文件中。

   1: public static class SelectExtensions
   2: {
   3:     public static MvcHtmlString DropDownList(this HtmlHelper htmlHelper, string name, string codeCategory, BindingOption bindingOption = null)
   4:     {
   5:         bindingOption = bindingOption ?? new BindingOption();
   6:         var listItems = GenerateListItems(codeCategory, bindingOption);
   7:         return htmlHelper.DropDownList(name, listItems, bindingOption.OptionalLabel);
   8:     }   
   9:     public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string codeCategory, BindingOption bindingOption = null)
  10:     {
  11:         bindingOption = bindingOption ?? new BindingOption();
  12:         var listItems = GenerateListItems(codeCategory, bindingOption);
  13:         return htmlHelper.DropDownListFor<TModel, TProperty>(expression, listItems,bindingOption.OptionalLabel);
  14:     }
  15:  
  16:     public static MvcHtmlString ListBox(this HtmlHelper htmlHelper, string name, string codeCategory, BindingOption bindingOption = null)
  17:     {
  18:         bindingOption = bindingOption ?? new BindingOption();
  19:         var listItems = GenerateListItems(codeCategory, bindingOption);
  20:         return htmlHelper.ListBox(name, listItems, bindingOption.OptionalLabel);
  21:     }
  22:     public static MvcHtmlString ListBoxFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string codeCategory, BindingOption bindingOption = null)
  23:     {
  24:         bindingOption = bindingOption ?? new BindingOption();
  25:         var listItems = GenerateListItems(codeCategory, bindingOption);
  26:         return htmlHelper.ListBoxFor<TModel, TProperty>(expression, listItems);
  27:     }
  28:  
  29:     public static IEnumerable<SelectListItem> GenerateListItems(string codeCategory, BindingOption bindingOption)
  30:     {
  31:         var items = new List<SelectListItem>();
  32:         foreach (var code in CodeManager.GetCodes(codeCategory).GetEffectiveCodes())
  33:         {
  34:             var item = new SelectListItem
  35:             {
  36:                 Text = FormatTemplate(bindingOption.TextTemplate, code),
  37:                 Value = FormatTemplate(bindingOption.ValueTemplate, code)
  38:             };
  39:             items.Add(item);
  40:         }
  41:         return items;
  42:     }
  43:  
  44:     private static string FormatTemplate(string template, CodeDescription code)
  45:     {
  46:         return template.Replace("{Id}", code.Id)
  47:             .Replace("{Code}", code.Code)
  48:             .Replace("{Description}", code.Description);
  49:     }
  50: }

三、使用这些扩展方法

现在我们创建一个简单的ASP.NET MVC应用来演示对DropDownList和ListBox的绑定。为此我们定义了如下一个Person类型,其Gender、MaritalStatus 和Country 属性分别对应于CodeManager维护的三组Code。在创建的HomeController中,我们将初始化Person对象的呈现定义在Index操作中。

   1: public class Person
   2: {
   3:     public string Name { get; set; }
   4:     public string Gender { get; set; }
   5:     [Display(Name = "MaritalStatus")]
   6:     public string MaritalStatus { get; set; }
   7:     public string Country { get; set; }
   8: }
   9:  
  10: public class HomeController : Controller
  11: {
  12:     public ActionResult Index()
  13:     {
  14:         return View(new Person
  15:         {
  16:             Name = "Zhan San",
  17:             Gender = "M",
  18:             Country = "CN",
  19:             MaritalStatus = "S"
  20:         });
  21:     }
  22: }

我们定义的扩展方法是用在Index操作定义的Index.cshtml视图中,下面是Index.cshtml的定义:

   1: @model CodeBinding.Models.Person
   2: @{
   3:     ViewBag.Title = "Index";
   4: }
   5:  
   6: <table>
   7:     <tr>
   8:         <td>@Html.LabelFor(m=>m.Name)</td>
   9:         <td>@Html.TextBoxFor(m=>m.Name)</td>
  10:     </tr>
  11:     <tr>
  12:         <td>@Html.LabelFor(m=>m.Gender)</td>
  13:         <td>@Html.DropDownListFor(m => m.Gender, "Gender", new BindingOption
  14:        {
  15:            OptionalLabel = "Please select your gender...",
  16:            TextTemplate = "{Code}-{Description}",
  17:            ValueTemplate = "{Code}"
  18:        })</td>
  19:     </tr>
  20:      <tr>
  21:         <td>@Html.LabelFor(m=>m.MaritalStatus)</td>
  22:         <td>@Html.DropDownListFor(m => m.MaritalStatus, "MaritalStatus",new BindingOption
  23:        {
  24:            OptionalLabel = "Please select your marital status...",
  25:            TextTemplate = "{Code}-{Description}",
  26:            ValueTemplate = "{Code}"
  27:        })</td>
  28:     </tr>
  29:      <tr>
  30:         <td>@Html.LabelFor(m=>m.Country)</td>
  31:         <td>@Html.ListBoxFor(m => m.Country, "Country")</td>
  32:     </tr>
  33: </table>

最后看看最终呈现出来的效果:

通过对HtmlHelper扩展简化“列表控件”的绑定
为HtmlHelper添加一个RadioButtonList扩展方法
在ASP.NET MVC中使用“RadioButtonList”和“CheckBoxList”

[ASP.NET MVC]通过对HtmlHelper扩展简化“列表控件”的绑定相关推荐

  1. 以编程方式在ASP.NET MVC中使用多个HTML Select控件

    目录 介绍 使用代码 使用JQuery 使用Razor和C# 兴趣点 介绍 很多时候,我们使用JavaScript或JQuery代码来操纵HTML控件,却不知道ASP.NET MVC与Razor和C# ...

  2. ASP.NET MVC CheckBoxFor为什么会生成hidden input控件

    自己开发的公众号,可以领取淘宝内部优惠券 @Html.CheckBoxFor(m => m.Bool) 使用CheckBoxFor方法得到的html代码会是下面这个样子 <input ch ...

  3. 用ASP.NET AJAX框架扩展HTML Map控件

    [摘要]在本文中,我将向你展示如何使用ASP.NET AJAX框架对添加可点击的热点的HTML Map控件进行扩展.经扩展后,当我们的鼠标移动到这些热点上后,即弹出关于这些热点的详细信息;但是,这些详 ...

  4. asp.net mvc源码分析-DefaultModelBinder 自定义的普通数据类型的绑定和验证

    asp.net mvc源码分析-DefaultModelBinder 自定义的普通数据类型的绑定和验证 原文:asp.net mvc源码分析-DefaultModelBinder 自定义的普通数据类型 ...

  5. 浅谈ASP.NET 4中构造“.NET研究”HTML5视频控件

    在本文中,将一步步地指导你如何使用Visual Studio 2010和ASP.NET 4的相关知识,打造一个基于HTML5标准规范的视频播放控件,其中你会学习到一些关于HTML 5的知识,还会学到如 ...

  6. ASP.NET开源框架之HIPPO技术内幕(五)--控件结构

    五.控件结构 上一章讲的是如何实现多语言的设计,本章来讲一下控件部分. 不管后端的代码多么完善,多么完美,最后都要以一定的形式展示出来,并且要使用灵活,这时就会用到控件. 在ASP的年代,去写这种控件 ...

  7. ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl

    第四章 组合控件开发CompositeControl 大家好,今天我们来实现一个自定义的控件,之前我们已经知道了,要开发自定义的控件一般继承三个基 类:Control,WebControl,还有一个就 ...

  8. ASP.NET自定义控件组件开发 第三章 为控件添加事件 后篇

    第三章 为控件添加事件 后篇 前一篇文章只是简单的说了下事件,但是大家应该方法,在ASP.NET自定义控件中只是简单那么定义事件是行不 通.如果大家开发的是WinForm中的事件,之前的定义可能没有什 ...

  9. ASP.NET自定义控件组件开发 第三章 为控件添加事件 前篇

    第三章 为控件添加事件 好了,我们之前以前开发一个控件.而且也添加了属性,开发也很规范,但是那个控件还差最后一点:添加事件. 系列文章链接: ASP.NET自定义控件组件开发 第一章 待续 ASP.N ...

最新文章

  1. C# 里怎样得到当前执行的函数名,当前代码行,源代码文件名。
  2. HDU-6290_奢侈的旅行(Dijstra+堆优化)
  3. Kalman Filter 学习笔记
  4. [BZOJ2599]Race
  5. python做一个窗口样式_[Python自学] PyQT5-窗口风格、窗口样式
  6. java背景图片加上组件_关于 java swing组件加背景图片的问题
  7. 提升研发效率 保障数据安全——阿里云宣布数据管理DMS企业版正式商业化 1
  8. Visual Object Classes Challenge 2012 (VOC2012) 简介
  9. js 导出Excel
  10. 时间格式转化大汇总各种类型
  11. 做python少儿编程教程-基于海龟编辑器python少儿编程
  12. c语言中xml的解析方式,浅谈Xml的三种解析方式
  13. Crust “方舟计划”播报# 3|Crust社区杰出贡献节点——20 位“开拓者”诞生
  14. Linux下Makefile的automake生成全攻略[zz]
  15. Tkx/tk——瞬态窗口
  16. 历代iphone详细对比
  17. Yocto系列讲解[理论篇]23 - BitBake全过程(1)
  18. 在数据库中,视图有什么用?什么时候需要用到视图?
  19. 2022电大国家开放大学网上形考任务-简明创新方法非免费(非答案)
  20. 用Ruby on Rails实现适应各种平台的在线Office文档预览

热门文章

  1. idea 配置mysql逆向_idea逆向工程配置
  2. java notifyall 唤醒顺序_Java线程中的notifyAll唤醒操作(推荐)
  3. mate20html查看器,华为Mate20系列迎重大升级 系统支持方舟编译器
  4. stretchlim函数
  5. 实用typescript_从今天开始,拿起 TypeScript 做一个轮子的制造者
  6. 强化学习组队学习task03—— 策略梯度及 PPO 算法
  7. java明星游戏_#IT明星不是梦#Java14不得不知的5个新功能
  8. python3.7语法错误_Tweepy不会安装在Python3.7上;显示“语法错误”
  9. 拓扑排序排课系统_木犀互联网技术周刊(第四十五期): 分布式系统简介
  10. pdf增强锐化软件_终于找到这款神器!高级锐化插件 让你的画面更清晰