学校如何建设网站首页网站开发资料
在《为HtmlHelper添加一个RadioButtonList扩展方法》中我通过对HtmlHelper和HtmlHelper<Model>的扩展使我们可以采用”RadioButtonList”的方式对一组类型为“radio”的<input>元素进行操作。昨天对对此进行了一些改进,并将“CheckBoxList”的功能添加进来。[源代码从这里下载]
一、有何特别之处?
和我的很多文章一样,旨在提供一种大体的解决方案,本解决方案旨在解决如下一些问题:
- 通过独立的组件对绑定到ListControl(ASP.NET Web Form的说法)的列表进行单独管理;
- 自动地调用上面这个组件获取列表信息进行相关Html的生成;
- 支持ASP.NET MVC原生的Model Binding。
二、实例演示
我们还是以《为HtmlHelper添加一个RadioButtonList扩展方法》例子来演示RadioButtonList和CheckBoxList用法。下面是代表个人信息同时作为Model的Person类型,Gender、MaritalStatus 和Country分别代表性别、婚姻状况和国籍(这里支持多国籍)。
1: public class Person
2: { 3: public string Name { get; set; }
4: public string Gender { get; set; }
5: [Display(Name = "Marital Status")]
6: public string MaritalStatus { get; set; }
7: public string[] Country { get; set; }
8: } 上述三个属性分别代表CodeManager这个独立组件维护的三个列表,CodeManager和代表列表选项的CodeDescription定义如下:
1: public class CodeDescription
2: { 3: public string Code { get; set; }
4: public string Description { get; set; }
5: public string Category{get;set;}
6: 7: public CodeDescription(string code, string description, string category)
8: { 9: this.Code = code;
10: this.Description = description;
11: this.Category = category;
12: } 13: } 14: public static class CodeManager
15: { 16: private static CodeDescription[] codes = new CodeDescription[]
17: { 18: new CodeDescription("M","Male","Gender"),
19: new CodeDescription("F","Female","Gender"),
20: new CodeDescription("S","Single","MaritalStatus"),
21: new CodeDescription("M","Married","MaritalStatus"),
22: new CodeDescription("CN","China","Country"),
23: new CodeDescription("US","Unite States","Country"),
24: new CodeDescription("UK","Britain","Country"),
25: new CodeDescription("SG","Singapore","Country")
26: }; 27: public static Collection<CodeDescription> GetCodes(string category)
28: { 29: Collection<CodeDescription> codeCollection = new Collection<CodeDescription>();
30: foreach(var code in codes.Where(code=>code.Category == category))
31: { 32: codeCollection.Add(code); 33: } 34: return codeCollection;
35: } 36: } 在默认的HomeController中,我们定义了如下两个Index方法,它们分别用于测试出栈数据(Model->UI)入栈数据(UI-〉Model)的绑定。
1: public class HomeController : Controller
2: { 3: public ActionResult Index()
4: { 5: return View(new Person { Name = "Foo", Gender = "M", MaritalStatus = "S", Country = new string[]{"CN","US"} });
6: } 7: [HttpPost] 8: public ActionResult Index(Person person)
9: { 10: return this.View(person);
11: } 12: } 下面是Index操作对应的View的定义,这是一个Model类型为Person的强类型View。对于Person的三个基于列表的属性,我们分别调用了自定义的扩展方法RadioButtonListFor和CheckBoxListFor进行了绑定。方法的最后两个参数分别代表通过CodeManager维护的列表的组别(Gender、MaritalStatus和Country),和同组RadioButton和CheckBox布局方向(水平或者纵向)。
1: @using System.Web.UI.WebControls 2: @model Person 3: @{ 4: ViewBag.Title = "Index"; 5: } 6: @using (Html.BeginForm()) 7: { 8: <table id="container">
9: <tr>
10: <td class="label">@Html.LabelFor(m => m.Name):</td>
11: <td>@Html.EditorFor(m => m.Name)</td>
12: </tr>
13: <tr>
14: <td class="label">@Html.LabelFor(m => m.Gender):</td>
15: <td>@Html.RadioButtonListFor(m => m.Gender, "Gender")</td>
16: </tr>
17: <tr>
18: <td class="label">@Html.LabelFor(m => m.MaritalStatus):</td>
19: <td>@Html.RadioButtonListFor(m => m.MaritalStatus, "MaritalStatus")</td>
20: </tr>
21: <tr>
22: <td class="label">@Html.LabelFor(m => m.Country):</td>
23: <td>@Html.CheckBoxListFor(m => m.Country, "Country", RepeatDirection.Vertical)</td>
24: </tr>
25: <tr>
26: <td colspan="2"><input type="submit" value="Save" /></td>
27: </tr>
28: </table>
29: } 下面是最终呈现出来的效果:

三、两组扩展方法具体实现
现在我们简单地来看看RadioButtonList/RadioButtonListFor和CheckBoxList/CheckBoxListFor这两组扩展方法的实现。我们通过CodeManager得到列表集合,通过HtmlHelper结合 ModelMetadata得到当前数据,最终借助于ListControlUtil的GenerateHtml生成相关的Html。
1: public static class ListControlExtensions
2: { 3: public static MvcHtmlString RadioButtonList(this HtmlHelper htmlHelper, string name, string codeCategory, RepeatDirection repeatDirection = RepeatDirection.Horizontal)
4: { 5: var codes = CodeManager.GetCodes(codeCategory); 6: return ListControlUtil.GenerateHtml(name, codes, repeatDirection,"radio",null);
7: } 8: public static MvcHtmlString RadioButtonListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string codeCategory, RepeatDirection repeatDirection = RepeatDirection.Horizontal)
9: { 10: var codes = CodeManager.GetCodes(codeCategory); 11: ModelMetadata metadata = ModelMetadata.FromLambdaExpression<TModel, TProperty>(expression, htmlHelper.ViewData); 12: string name = ExpressionHelper.GetExpressionText(expression);
13: string fullHtmlFieldName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
14: return ListControlUtil.GenerateHtml(fullHtmlFieldName, codes, repeatDirection, "radio", metadata.Model);
15: } 16: 17: public static MvcHtmlString CheckBoxList(this HtmlHelper htmlHelper, string name, string codeCategory, RepeatDirection repeatDirection = RepeatDirection.Horizontal)
18: { 19: var codes = CodeManager.GetCodes(codeCategory); 20: return ListControlUtil.GenerateHtml(name, codes, repeatDirection, "checkbox", null);
21: } 22: public static MvcHtmlString CheckBoxListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string codeCategory, RepeatDirection repeatDirection = RepeatDirection.Horizontal)
23: { 24: var codes = CodeManager.GetCodes(codeCategory); 25: ModelMetadata metadata = ModelMetadata.FromLambdaExpression<TModel, TProperty>(expression, htmlHelper.ViewData); 26: string name = ExpressionHelper.GetExpressionText(expression);
27: string fullHtmlFieldName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
28: return ListControlUtil.GenerateHtml(fullHtmlFieldName, codes, repeatDirection, "checkbox", metadata.Model);
29: } 30: } ListControlUtil中生成相关Html的逻辑定义如下:
1: public static class ListControlUtil
2: { 3: public static MvcHtmlString GenerateHtml(string name, Collection<CodeDescription> codes, RepeatDirection repeatDirection, string type, object stateValue)
4: { 5: TagBuilder table = new TagBuilder("table");
6: int i = 0;
7: bool isCheckBox = type == "checkbox";
8: if (repeatDirection == RepeatDirection.Horizontal)
9: { 10: TagBuilder tr = new TagBuilder("tr");
11: foreach (var code in codes)
12: { 13: i++; 14: string id = string.Format("{0}_{1}", name, i);
15: TagBuilder td = new TagBuilder("td");
16: 17: bool isChecked = false;
18: if (isCheckBox)
19: { 20: IEnumerable<string> currentValues = stateValue as IEnumerable<string>;
21: isChecked = (null != currentValues && currentValues.Contains(code.Code));
22: } 23: else
24: { 25: string currentValue = stateValue as string;
26: isChecked = (null != currentValue && code.Code == currentValue);
27: } 28: 29: td.InnerHtml = GenerateRadioHtml(name, id, code.Description, code.Code, isChecked,type); 30: tr.InnerHtml += td.ToString(); 31: } 32: table.InnerHtml = tr.ToString(); 33: } 34: else
35: { 36: foreach (var code in codes)
37: { 38: TagBuilder tr = new TagBuilder("tr");
39: i++; 40: string id = string.Format("{0}_{1}", name, i);
41: TagBuilder td = new TagBuilder("td");
42: 43: bool isChecked = false;
44: if (isCheckBox)
45: { 46: IEnumerable<string> currentValues = stateValue as IEnumerable<string>;
47: isChecked = (null != currentValues && currentValues.Contains(code.Code));
48: } 49: else
50: { 51: string currentValue = stateValue as string;
52: isChecked = (null != currentValue && code.Code == currentValue);
53: } 54: 55: td.InnerHtml = GenerateRadioHtml(name, id, code.Description, code.Code, isChecked, type); 56: tr.InnerHtml = td.ToString(); 57: table.InnerHtml += tr.ToString(); 58: } 59: } 60: return new MvcHtmlString(table.ToString());
61: } 62: 63: private static string GenerateRadioHtml(string name, string id, string labelText, string value, bool isChecked, string type)
64: { 65: StringBuilder sb = new StringBuilder();
66: 67: TagBuilder label = new TagBuilder("label");
68: label.MergeAttribute("for", id);
69: label.SetInnerText(labelText); 70: 71: TagBuilder input = new TagBuilder("input");
72: input.GenerateId(id); 73: input.MergeAttribute("name", name);
74: input.MergeAttribute("type", type);
75: input.MergeAttribute("value", value);
76: if (isChecked)
77: { 78: input.MergeAttribute("checked", "checked");
79: } 80: sb.AppendLine(input.ToString()); 81: sb.AppendLine(label.ToString()); 82: return sb.ToString();
83: } 84: }
通过对HtmlHelper扩展简化“列表控件”的绑定
为HtmlHelper添加一个RadioButtonList扩展方法
在ASP.NET MVC中使用“RadioButtonList”和“CheckBoxList”
微信公众账号:大内老A
微博: www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号 蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
