【问题标题】:How to create a CheckBoxListFor extension method in ASP.NET MVC?如何在 ASP.NET MVC 中创建 CheckBoxListFor 扩展方法?
【发布时间】:2011-04-22 19:25:33
【问题描述】:

我知道在 ASP.NET MVC Html helper 扩展方法中有一个ListBoxFor 扩展方法,但我一直认为复选框列表比列表框更易于使用。

在良好的旧 WebForms 中有一个非常方便的 CheckBoxList 控件,但显然现在已经不存在了。

问题是,为什么在 ASP.NET MVC 中没有办法创建复选框列表?我如何编写自己的扩展方法来创建复选框列表并以类似ListBoxFor 的行为方式运行?

【问题讨论】:

    标签: .net asp.net asp.net-mvc checkboxlist


    【解决方案1】:

    这里是 CheckBoxListFor 的强类型 HtmlHelper,它将所选项目作为视图数据模型中的数组处理。我选择不包装 Html.CheckBox 或 Html.CheckBoxFor 方法,因为我不想在我的复选框列表中隐藏“假”字段。

    请随时改进并重新发布:-)

    //View
    
    <%: Html.CheckBoxListFor(model => model.FreightTypeIds, FreightTypeMultiSelectList)  %>
    
    //Controller
    
        public ActionResult SomeAction(int[] FreightTypeIds)
        {
           //...
    
           return View();
        }
    
    
    //Extension
    public static MvcHtmlString CheckBoxListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, IEnumerable<TProperty>>> expression, MultiSelectList allOptions, object htmlAttributes = null)
    {
        ModelMetadata modelMetadata = ModelMetadata.FromLambdaExpression<TModel, IEnumerable<TProperty>>(expression, htmlHelper.ViewData);
    
        // Derive property name for checkbox name
        string propertyName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(modelMetadata.PropertyName);
    
        // Get currently select values from the ViewData model
        IEnumerable<TProperty> list = expression.Compile().Invoke(htmlHelper.ViewData.Model);
    
        // Convert selected value list to a List<string> for easy manipulation
        IList<string> selectedValues = new List<string>();
    
        if (list != null)
        {
            selectedValues = new List<TProperty>(list).ConvertAll<string>(delegate(TProperty i) { return i.ToString(); });
        }
    
        // Create div
        TagBuilder divTag = new TagBuilder("div");
        divTag.MergeAttributes(new RouteValueDictionary(htmlAttributes), true);
    
        // Add checkboxes
        foreach (SelectListItem item in allOptions)
        {
            divTag.InnerHtml += string.Format(
                                              "<div><input type=\"checkbox\" name=\"{0}\" id=\"{1}_{2}\" " +
                                              "value=\"{2}\" {3} /><label for=\"{1}_{2}\">{4}</label></div>",
                                              propertyName,
                                              TagBuilder.CreateSanitizedId(propertyName),
                                              item.Value,
                                              selectedValues.Contains(item.Value) ? "checked=\"checked\"" : string.Empty,
                                              item.Text);
        }
    
         return MvcHtmlString.Create(divTag.ToString());
    }
    

    【讨论】:

    • 谢谢,这似乎就是我想要的。回家后试试看。
    • 经过一些修改,我成功地让它按我想要的方式工作。非常感谢您的代码! :)
    • @RafaelSoares 你打算做什么样的验证?至少有一个必须打勾或类似的东西?
    • @RafaelSoares - 在这种情况下,我倾向于使用隐藏字段,例如“CheckboxChecked”没有初始值,上面有“必需”验证消息。然后我将一些 jquery 连接到复选框,以便如果一个或多个复选框被“选中”,则隐藏字段中的值设置为 true|yes|ok 或其他任何值。如果没有检查,只需从隐藏字段中删除值,验证就可以工作了。
    • 如果你将这个嵌套在 EditorFor 中,它将无法正确绑定。我必须从 htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(modelMetadata.PropertyName); 设置 propertyName 变量然后使用带有 TagBuilder.CreateSanitizedId() 的经过清理的 id
    【解决方案2】:

    我仍在尝试,但这似乎与默认活页夹相处融洽,并在发布后保留用户选择。隐藏字段,真的吗? ..这会在html5中飞行吗?这感觉很疯狂,但我宁愿这样做,也不愿仅仅因为 ModelState.IsValid 为假而点击我的数据库以获取下拉列表和复选框列表。

            public static MvcHtmlString CheckBoxList(this HtmlHelper htmlHelper, List<SelectListItem> list, string ModelCollectionName)
        {
            var sb = new StringBuilder();
    
            if (list != null)
            {
                int i = 0;
    
                foreach (var l in list)
                {
                    string collectionNameIndex = String.Format("{0}[{1}]", ModelCollectionName, i);
    
                    var hiddenName = new TagBuilder("input");
                    hiddenName.Attributes.Add(new KeyValuePair<string, string>("type", "hidden"));
                    hiddenName.Attributes.Add(new KeyValuePair<string, string>("name", String.Format("{0}.{1}", collectionNameIndex, "Text")));
                    hiddenName.Attributes.Add(new KeyValuePair<string, string>("value", l.Text));
    
                    var hiddenValue = new TagBuilder("input");
                    hiddenValue.Attributes.Add(new KeyValuePair<string, string>("type", "hidden"));
                    hiddenValue.Attributes.Add(new KeyValuePair<string, string>("name", String.Format("{0}.{1}", collectionNameIndex, "Value")));
                    hiddenValue.Attributes.Add(new KeyValuePair<string, string>("value", l.Value));
    
                    var checkBoxTag = htmlHelper.CheckBox(String.Format("{0}.{1}", collectionNameIndex, "Selected"), l.Selected);
    
                    var labelTag = new TagBuilder("label");
                    labelTag.Attributes.Add(new KeyValuePair<string, string>("for", String.Format("{0}.{1}", collectionNameIndex, "Name")));
                    labelTag.SetInnerText(l.Text);
    
                    sb.Append(hiddenName);
                    sb.Append(hiddenValue);
                    sb.Append(checkBoxTag);
                    sb.Append(labelTag);
                    sb.Append("<br/>");
    
                    i++;
                }
            }
    
            return MvcHtmlString.Create(sb.ToString());
        }
    

    【讨论】:

      【解决方案3】:

      虽然微软员工可能是唯一可以回答为什么不存在此类帮助方法的人,但您可以尝试:

      型号:

      public class MyViewModel
      {
          public bool[] Values { get; set; }
      }
      

      控制器:

      public class HomeController : Controller
      {
          public ActionResult Index()
          {
              return View(new MyViewModel 
              { 
                  Values = new[] { true, false, true, false }
              });
          }
      
          [HttpPost]
          public ActionResult Index(MyViewModel model)
          {
              return View(model);
          }
      }
      

      查看:

      <% using (Html.BeginForm()) { %>
          <%: Html.EditorFor(x => x.Values) %>
          <input type="submit" value="OK" />
      <% } %>
      

      如您所见,EditorFor 将处理所需的一切。

      【讨论】:

      • 这是个好主意,但正如我所说,我想要类似于ListBoxFor 的行为。
      • 你能再具体一点吗? ListBoxFor 生成 &lt;select&gt; 并接受不同的类型。你到底需要什么?
      【解决方案4】:

      您可能对 Jeremiah Clark 的 CheckBoxList Helper for MVC 文章感兴趣(不幸的是,它的日期为 2008 年 11 月,涉及 MVC 1)。

      【讨论】:

      • 这篇文章不错,但写的时候并没有考虑到强类型的 HTML 助手。
      猜你喜欢
      • 1970-01-01
      • 2010-11-10
      • 2022-06-11
      • 1970-01-01
      • 1970-01-01
      • 2019-07-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多