您的位置:首页 > 编程语言 > ASP

在ASP.NET MVC中使用“RadioButtonList”和“CheckBoxList”

2012-03-16 10:11 1056 查看
在《为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分别代表性别、婚姻状况和国籍(这里支持多国籍)。

[code]      public class Person

     {

         public string Name { get; set; }

         public string Gender { get; set; }

         [Display(Name = "Marital Status")]

         public string MaritalStatus { get; set; }

         public string[] Country { get; set; }

     }

[/code]

上述三个属性分别代表CodeManager这个独立组件维护的三个列表,CodeManager和代表列表选项的CodeDescription定义如下:

[code]
     public class CodeDescription

     {

         public string Code { get; set; }

         public string Description { get; set; }

         public string Category{get;set;}

      

         public CodeDescription(string code, string description, string category)

         {

             this.Code = code;

             this.Description = description;

             this.Category = category;

         }

     }

     public static class CodeManager

     {

         private static CodeDescription[] codes = new CodeDescription[]

         {

             new CodeDescription("M","Male","Gender"),

             new CodeDescription("F","Female","Gender"),

             new CodeDescription("S","Single","MaritalStatus"),

             new CodeDescription("M","Married","MaritalStatus"),

             new CodeDescription("CN","China","Country"),

             new CodeDescription("US","Unite States","Country"),

             new CodeDescription("UK","Britain","Country"),

             new CodeDescription("SG","Singapore","Country")

         };

         public static Collection<CodeDescription> GetCodes(string category)

         {

             Collection<CodeDescription> codeCollection = new Collection<CodeDescription>();

             foreach(var code in codes.Where(code=>code.Category == category))

             {

                 codeCollection.Add(code);

             }

             return codeCollection;

         }

     }

[/code]

在默认的HomeController中,我们定义了如下两个Index方法,它们分别用于测试出栈数据(Model->UI)入栈数据(UI-〉Model)的绑定。

[code]
     public class HomeController : Controller

     {

         public ActionResult Index()

         {

             return View(new Person { Name = "Foo", Gender = "M", MaritalStatus = "S", Country = new string[]{"CN","US"} });

         }

         [HttpPost]

         public ActionResult Index(Person person)

         {

             return this.View(person);

         }

     }

[/code]

下面是Index操作对应的View的定义,这是一个Model类型为Person的强类型View。对于Person的三个基于列表的属性,我们分别调用了自定义的扩展方法RadioButtonListFor和CheckBoxListFor进行了绑定。方法的最后两个参数分别代表通过CodeManager维护的列表的组别(Gender、MaritalStatus和Country),和同组RadioButton和CheckBox布局方向(水平或者纵向)。

[code]
     @using System.Web.UI.WebControls

     @model Person

     @{

         ViewBag.Title = "Index";

     }

     @using (Html.BeginForm())

     { 

         <table id="container">

             <tr>

                 <td class="label">@Html.LabelFor(m => m.Name):</td>

                 <td>@Html.EditorFor(m => m.Name)</td>

             </tr>

              <tr>

                 <td class="label">@Html.LabelFor(m => m.Gender):</td>

                 <td>@Html.RadioButtonListFor(m => m.Gender, "Gender")</td>

             </tr>

              <tr>

                 <td class="label">@Html.LabelFor(m => m.MaritalStatus):</td>

                 <td>@Html.RadioButtonListFor(m => m.MaritalStatus, "MaritalStatus")</td>

             </tr>

              <tr>

                 <td class="label">@Html.LabelFor(m => m.Country):</td>

                 <td>@Html.CheckBoxListFor(m => m.Country, "Country", RepeatDirection.Vertical)</td>

             </tr> 

             <tr>

                 <td colspan="2"><input type="submit" value="Save" /></td>

             </tr>      

         </table>    

     }

[/code]

下面是最终呈现出来的效果:





三、两组扩展方法具体实现

现在我们简单地来看看RadioButtonList/RadioButtonListFor和CheckBoxList/CheckBoxListFor这两组扩展方法的实现。我们通过CodeManager得到列表集合,通过HtmlHelper结合 ModelMetadata得到当前数据,最终借助于ListControlUtil的GenerateHtml生成相关的Html。

[code]
     public static class ListControlExtensions

     {

         public static MvcHtmlString RadioButtonList(this HtmlHelper htmlHelper, string name, string codeCategory, RepeatDirection repeatDirection = RepeatDirection.Horizontal)

         {

             var codes = CodeManager.GetCodes(codeCategory);

             return ListControlUtil.GenerateHtml(name, codes, repeatDirection,"radio",null);

         }

         public static MvcHtmlString RadioButtonListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string codeCategory, RepeatDirection repeatDirection = RepeatDirection.Horizontal)

         {

             var codes = CodeManager.GetCodes(codeCategory);

             ModelMetadata metadata = ModelMetadata.FromLambdaExpression<TModel, TProperty>(expression, htmlHelper.ViewData);

             string name = ExpressionHelper.GetExpressionText(expression);           

             string fullHtmlFieldName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);

             return ListControlUtil.GenerateHtml(fullHtmlFieldName, codes, repeatDirection, "radio", metadata.Model);

         }

      

         public static MvcHtmlString CheckBoxList(this HtmlHelper htmlHelper, string name, string codeCategory, RepeatDirection repeatDirection = RepeatDirection.Horizontal)

         {

             var codes = CodeManager.GetCodes(codeCategory);

             return ListControlUtil.GenerateHtml(name, codes, repeatDirection, "checkbox", null);

         }

         public static MvcHtmlString CheckBoxListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string codeCategory, RepeatDirection repeatDirection = RepeatDirection.Horizontal)

         {

             var codes = CodeManager.GetCodes(codeCategory);

             ModelMetadata metadata = ModelMetadata.FromLambdaExpression<TModel, TProperty>(expression, htmlHelper.ViewData);

             string name = ExpressionHelper.GetExpressionText(expression);

             string fullHtmlFieldName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);

             return ListControlUtil.GenerateHtml(fullHtmlFieldName, codes, repeatDirection, "checkbox", metadata.Model);

         }

     }

[/code]

ListControlUtil中生成相关Html的逻辑定义如下:

[code]
     public static class ListControlUtil

     {

         public static MvcHtmlString GenerateHtml(string name, Collection<CodeDescription> codes, RepeatDirection repeatDirection, string type, object stateValue)

         {

             TagBuilder table = new TagBuilder("table");

             int i = 0;

             bool isCheckBox = type == "checkbox";

             if (repeatDirection == RepeatDirection.Horizontal)

             {

                 TagBuilder tr = new TagBuilder("tr");

                 foreach (var code in codes)

                 {

                     i++;

                     string id = string.Format("{0}_{1}", name, i);

                     TagBuilder td = new TagBuilder("td");

      

                     bool isChecked = false;

                     if (isCheckBox)

                     {

                         IEnumerable<string> currentValues = stateValue as IEnumerable<string>;

                         isChecked = (null != currentValues && currentValues.Contains(code.Code));

                     }

                     else

                     {

                         string currentValue = stateValue as string;

                         isChecked = (null != currentValue && code.Code == currentValue);

                     }

      

                     td.InnerHtml = GenerateRadioHtml(name, id, code.Description, code.Code, isChecked,type);

                     tr.InnerHtml += td.ToString();

                 }

                 table.InnerHtml = tr.ToString();

             }

             else

             {

                 foreach (var code in codes)

                 {

                     TagBuilder tr = new TagBuilder("tr");

                     i++;

                     string id = string.Format("{0}_{1}", name, i);

                     TagBuilder td = new TagBuilder("td");

      

                     bool isChecked = false;

                     if (isCheckBox)

                     {

                         IEnumerable<string> currentValues = stateValue as IEnumerable<string>;

                         isChecked = (null != currentValues && currentValues.Contains(code.Code));

                     }

                     else

                     {

                         string currentValue = stateValue as string;

                         isChecked = (null != currentValue && code.Code == currentValue);

                     }

      

                     td.InnerHtml = GenerateRadioHtml(name, id, code.Description, code.Code, isChecked, type);

                     tr.InnerHtml = td.ToString();

                     table.InnerHtml += tr.ToString();

                 }

             }

             return new MvcHtmlString(table.ToString());

         }

      

         private static string GenerateRadioHtml(string name, string id, string labelText, string value, bool isChecked, string type)

         {

             StringBuilder sb = new StringBuilder();

      

             TagBuilder label = new TagBuilder("label");

             label.MergeAttribute("for", id);

             label.SetInnerText(labelText);

      

             TagBuilder input = new TagBuilder("input");

             input.GenerateId(id);

             input.MergeAttribute("name", name);

             input.MergeAttribute("type", type);

             input.MergeAttribute("value", value);

             if (isChecked)

             {

                 input.MergeAttribute("checked", "checked");

             }

             sb.AppendLine(input.ToString());

             sb.AppendLine(label.ToString());

             return sb.ToString();

         }

     }

[/code]



通过对HtmlHelper扩展简化“列表控件”的绑定


为HtmlHelper添加一个RadioButtonList扩展方法


在ASP.NET MVC中使用“RadioButtonList”和“CheckBoxList”
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: