在ASP.NET MVC中使用“RadioButtonList”和“CheckBoxList”
在《為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
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁麵明顯位置給出原文連接,否則保留追究法律責任的權利。
最後更新:2017-10-26 12:04:22