zoukankan      html  css  js  c++  java
  • 在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”

    作者:Artech
    出处:http://artech.cnblogs.com/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    两条斜线
    Cantor表
    城市网络
    一起来数二叉树吧
    牛客网音乐研究(枚举)
    删括号
    合并回文子串
    寻找道路
    EXTJS 4.0.2 XML数据
    extjs4.0.2a gridpanel看不到横向滚动条的一种原因
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2402292.html
Copyright © 2011-2022 走看看