ASP .NET MVC HtmlHelper扩展——简化“列表控件”的绑定
在众多表单元素中,有一类<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>
最后看看最终呈现出来的效果:
ASP .NET MVC HtmlHelper扩展——简化“列表控件”的绑定的更多相关文章
- 在ASP.NET MVC 中使用ActiveReports报表控件
随着MVC模式的广泛运用,对Web应用系统的开发带来了巨大的影响,我们好像又回到了原来的ASP时代,视乎这是一种后退而不是一种进步,不过MVC模式给我们带来的影响不仅限于我们所看到的这一点..MVC看 ...
- ASP.NET中后台数据和前台控件的绑定
关于ASP.NET中后台数据库和前台的数据控件的绑定问题 最近一直在学习个知识点,自己创建了SQL Server数据库表,想在ASP.NET中连接数据库,并把数据库中的数据显示在前台,注意,这里的数据 ...
- [转]ASP.NET MVC HtmlHelper扩展之Calendar日期时间选择
本文转自:http://blog.bossma.cn/asp_net_mvc/asp-net-mvc-htmlhelper-calendar-datetime-select/ 这里我们扩展HtmlHe ...
- ASP.NET MVC 页面使用富文本控件的XSS漏洞问题
目前在做的项目存在XSS安全漏洞! 原因是有一些页面使用了富文本编辑框,为了使得其内容可以提交,为相关action设置了[ValidateInput(false)] 特性: [HttpPost] [V ...
- 扩展ASP.NET MVC HtmlHelper类
在这篇帖子中我会使用一个示例演示扩展ASP.NET MVC HtmlHelper类,让它们可以在你的MVC视图中工作.这个示例中我会提供一个简单的方案生成Html表格. HtmlHelper类 Htm ...
- MVC HtmlHelper扩展——实现分页功能
MVC HtmlHelper扩展类(PagingHelper) using System; using System.Collections.Generic; using System.Collect ...
- ASP.NET MVC HtmlHelper用法集锦
ASP.NET MVC HtmlHelper用法集锦 在写一个编辑数据的页面时,我们通常会写如下代码 1:<inputtype="text"value='<%=View ...
- WPF自定义控件与样式(7)-列表控件DataGrid与ListView自定义样式
一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要内容: Dat ...
- asp.net中遍历界面上所有控件进行属性设置
* 使用方法: * 前台页面调用方法,重置: protected void Reset_Click(object sender, EventArgs e) { ...
随机推荐
- spring web参数传递
spring boot 参数相关 ****************************************** @RequestParam 这个注解用来绑定单个请求数据,既可以是url中的 ...
- 顺序队列(C语言)
#define Queue_MAX_SIZE 20 #define OK 1 #define ERROR 0 #include <stdio.h> #include <stdlib. ...
- LVS、Nginx 及 HAProxy 工作原理
当前大多数的互联网系统都使用了服务器集群技术,集群是将相同服务部署在多台服务器上构成一个集群整体对外提供服务,这些集群可以是 Web 应用服务器集群,也可以是数据库服务器集群,还可以是分布式缓存服务器 ...
- validatord的使用方法理解
今天是周日,自己已经在公司上班一周啦,可是这是我感觉最难熬 一周之一,上一次还是在高考失利的时候,自己整整一个月没有出去,在家里呆着,不知道干什么,这一此自己也是,感觉自己很难在这个公司熬下去,但是, ...
- ota升级动画修改
在网上可以搜到很多相关的文章,但是很多文章都是复制粘贴而来的,为了方便后面工作学习,本文会把其中最关键的几个步骤列出来. 首先根据ota升级界面的文字可以确认相关的图片资源的目录在哪里,可以网上搜一下 ...
- nginx安装以及调优
目录: 1.安装nginx 2.配置nginx 3.调优nginx 4.性能测试 ps:为了方便,文档使用docker容器来操作的. 1.安装nginx 1.1 启动容器.download nginx ...
- Oracle数据库查询基本数据
------------------------------------------------------------------找出EMP表select * from EMP;--选择在部门30中 ...
- Runtime之方法
前两篇介绍了类与对象.成员变量&属性&关联对象的相关知识,本篇我们将开始讲解Runtime中最有意思的一部分内容:消息处理机制.我们从一个示例开始. 在OC中,我们使用下面这种方式来调 ...
- linux(centos7)安装docker
1.检查内核版本,必须是3.10及以上 uname ‐r 2.安装docker yum install docker 3.输入y确认安装 4.启动docker [root@localhost ~]# ...
- Centos7.x gnome 桌面美化
一.管理工具 gnome是通过gnome-tweak-tool(优化工具)来管理的,可以在左上角的应用程序->工具里找到. 也可以直接在终端输入gnome-tweak-tool来启动它.启动界面 ...