[ASP.NET MVC]为HtmlHelper添加一个RadioButtonList扩展方法

前面一篇文章中,我们通过对HtmlHelper的扩展简化了对DropDownList(Single-Line-Select)和ListBox(Multiple-Line-Select)的绑定,以及对作为数据源的列表进行单独维护。现在我们为HtmlHelper/HtmlHelper<Model>添加一个RadioButtonList/RadioButtonListFor扩展方法实现一组RadioButton的绑定。[源代码从这里下载]

一、RadioButtonListFor的使用

我们先来显示一下扩展的RadioButtonListFor的方法的用法。如下所示的是作为Model的Person类型,其Gender(Male/Female)、MaritalStatus(Single/Married)和Country的选项列表通过独立的组件CodeManager进行单独维护。

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

在一个针对Person对象进行编辑的强类型View(以Person作为Model)中我们进行了如下的定义。RadioButtonListFor方的最后一个参数(“Gender”、“MaritalStatus”和“Country”)表示对应列表的类别。

   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.RadioButtonListFor(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: }

下面这张图表示上面这个View在浏览器中呈现出来的样式,我们可以看到三组RadioButton被有效地生成出来。

二、维护选项列表的组件CodeManager

由于在一个应用中,作为绑定到“列表控件”上的选项列表可能会有很多,将它们进行单独地维护是一个理想的选择。作为模拟,我们创建了如下一个简单的CodeManager组件。我们将列表中的某个选项通过CodeDescription,其三个属性Code、Description分别表示其“值”和“显示文本”,Category表示类别(通过它对列表项进行分组)。CodeManager通过一个静态字段作为列表数据的存储,上面例子中使用到的三组列表维护于此。GetCodes方法用于返回指定“类别”的列表选项。

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

三、RadioButtonList/RadioButtonListFor扩展方法

如下所示的是RadioButtonList/RadioButtonListFor两个扩展方法的定义,参数codeCategory表示作为数据源的列表类别,而RepeatDirection 枚举类型则代表同组的RadioButton的排列方向,默认为水平。从上面的例子我们可以看到,我们通过这个参数将名称为Country的RadioButtonList进行了纵向排列。通过Html生成代码我们可以看出,我们采用了Table作为布局方式,实际上ASP.NET的RadioButtonList也是这么做的。

   1: public static  class RadioButtonListExtensions
   2: {
   3:     public static MvcHtmlString RadioButtonList(this HtmlHelper htmlHelper, string name,  string codeCategory, RepeatDirection repeatDirection = RepeatDirection.Horizontal, IDictionary<string, object> htmlAttributes = null)
   4:     {
   5:         var codes = CodeManager.GetCodes(codeCategory);
   6:         return GenerateHtml(name, codes, repeatDirection, htmlAttributes, null);
   7:     }
   8:     public static MvcHtmlString RadioButtonListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string codeCategory, RepeatDirection repeatDirection =  RepeatDirection.Horizontal, IDictionary<string, object> htmlAttributes = null)
   9:     {
  10:         var codes = CodeManager.GetCodes(codeCategory);
  11:         
  12:         ModelMetadata metadata = ModelMetadata.FromLambdaExpression<TModel, TProperty>(expression, htmlHelper.ViewData);
  13:         string name = ExpressionHelper.GetExpressionText(expression);
  14:         var attributes = htmlHelper.GetUnobtrusiveValidationAttributes(name, metadata);
  15:         foreach (var item in attributes)
  16:         {
  17:             htmlAttributes.Add(item);
  18:         }
  19:         string fullHtmlFieldName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
  20:         string stateValue = (string)metadata.Model;
  21:         return GenerateHtml(fullHtmlFieldName, codes, repeatDirection, htmlAttributes, stateValue);
  22:     }
  23:     private static MvcHtmlString GenerateHtml(string name, Collection<CodeDescription> codes, RepeatDirection repeatDirection, IDictionary<string, object> htmlAttributes, string stateValue = null)
  24:     {
  25:         TagBuilder table = new TagBuilder("table");
  26:         int i = 0;
  27:         if (repeatDirection == RepeatDirection.Horizontal)
  28:         {
  29:             TagBuilder tr = new TagBuilder("tr");
  30:             foreach (var code in codes)
  31:             {
  32:                 i++;
  33:                 string id = string.Format("{0}_{1}", name, i);
  34:                 TagBuilder td = new TagBuilder("td");
  35:                 td.InnerHtml = GenerateRadioHtml(name, id, code.Description, code.Code, (stateValue != null && stateValue == code.Code), htmlAttributes);
  36:                 tr.InnerHtml+=td.ToString();
  37:             }
  38:             table.InnerHtml = tr.ToString();
  39:         }
  40:         else
  41:         {
  42:             foreach (var code in codes)
  43:             {
  44:                 TagBuilder tr = new TagBuilder("tr");
  45:                 i++;
  46:                 string id = string.Format("{0}_{1}", name, i);
  47:                 TagBuilder td = new TagBuilder("td");
  48:                 td.InnerHtml = GenerateRadioHtml(name, id, code.Description, code.Code, (stateValue != null && stateValue == code.Code), htmlAttributes);
  49:                 tr.InnerHtml = td.ToString();
  50:                 table.InnerHtml += tr.ToString();
  51:             }
  52:         }
  53:         return new MvcHtmlString(table.ToString());
  54:     }
  55:  
  56:     private static string GenerateRadioHtml(string name, string id, string labelText, string value, bool isChecked, IDictionary<string, object> htmlAttributes)
  57:     {
  58:         StringBuilder sb = new StringBuilder();
  59:  
  60:         TagBuilder label = new TagBuilder("label");
  61:         label.MergeAttribute("for", id);
  62:         label.SetInnerText(labelText);
  63:  
  64:         TagBuilder input = new TagBuilder("input");
  65:         input.GenerateId(id);
  66:         input.MergeAttribute("name", name);
  67:         input.MergeAttribute("type", "radio");
  68:         input.MergeAttribute("value", value);
  69:         input.MergeAttributes(htmlAttributes);
  70:         if (isChecked)
  71:         {
  72:             input.MergeAttribute("checked", "checked");
  73:         }
  74:         sb.AppendLine(input.ToString());
  75:         sb.AppendLine(label.ToString());
  76:         return sb.ToString();
  77:     }
  78: }

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏tkokof 的技术,小趣及杂念

Sweet Snippet 系列之 有序列表

很朴素的一种想法,为了维持 List 有序,我们可以在 Add 操作之后进行 Sort 操作(Remove 操作后不需要重新 Sort):

5210
来自专栏草根专栏

使用两种方法让 ASP.NET Core 实现遵循 HATEOAS 结构的 RESTful API

HATEOAS(Hypermedia as the engine of application state)是 REST 架构风格中最复杂的约束,也是构建成熟 ...

588110
来自专栏函数式编程语言及工具

FunDA(16)- 示范:整合并行运算 - total parallelism solution

   在对上两篇讨论中我们介绍了并行运算的两种体现方式:并行构建数据源及并行运算用户自定义函数。我们分别对这两部分进行了示范。本篇我准备示范把这两种情况集成一体...

207100
来自专栏日常工作总结

MVC中JSON字符长度超出限制的异常处理

使用 JSON JavaScriptSerializer 进行序列化或反序列化时出错。字符串的长度超过了为 maxJsonLength 属性设置的值。

31930
来自专栏偏前端工程师的驿站

网页优化系列三:使用压缩后置viewstate

  Asp.net中的服务器控件都启用了viewstate,虽然方便了开发人员,但页面大小及性能上确实有所影响,对于无需viewstate的控件及页面可以直接把...

21550
来自专栏草根专栏

从头编写 asp.net core 2.0 web api 基础框架 (5) EF CRUD

Github源码地址:https://github.com/solenovex/Building-asp.net-core-2-web-api-starter-...

41760
来自专栏SDNLAB

ONOS集群选举分析

首先简单介绍下自己,之前是做 floodlight 控制器开发的,鉴于 ODL 和 onos 的如火如荼的发展,如果不对了解点就感觉自己 OUT 了,因此忙里偷...

37360
来自专栏海天一树

小朋友学C语言(29):switch case语句

switch case语句与if elseif语句类似,都是从多个选择条件里选取一个来执行。 (一)先来看一个if elseif程序 #include <std...

32390
来自专栏GIS讲堂

一个GISER 6.7的祝福

一年一度的高考今天开始了,回想10年前,那是我第一次高考;10年后,作为一个GISER,在此给大家献上一个GISER的祝福,祝愿各位考生:考神附体,考完报考GI...

15340
来自专栏跟着阿笨一起玩NET

如何让DevExpress TreeList的每个结点高亮显示?

原文地址:http://www.devexpresscn.com/devResources/page-18-78.html

20020

扫码关注云+社区

领取腾讯云代金券