閱讀606 返回首頁    go 阿裏雲 go 技術社區[雲棲]


在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: }

下麵是最終呈現出來的效果:

image

現在我們簡單地來看看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

  上一篇:go  [ASP.NET MVC]為HtmlHelper添加一個RadioButtonList擴展方法
  下一篇:go  為什麼GAC和VS引用的程序集不一致?