如何在 ASP.NET MVC 中创建 CheckBoxListFor 扩展方法?

Posted

技术标签:

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

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

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

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

【问题讨论】:

【参考方案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 助手。

以上是关于如何在 ASP.NET MVC 中创建 CheckBoxListFor 扩展方法?的主要内容,如果未能解决你的问题,请参考以下文章

我们如何使用 EF 在 ASP.Net MVC 应用程序中创建 3 层架构?

如何在 asp.net mvc 中创建审计日志/审计跟踪

如何在 Visual Studio 2017 的 ASP.NET MVC 中创建自定义生成/脚手架模板(Razor)?

如何在 ASP .net MVC 4 应用程序的 HTML5 中创建带有可点击选项的水平条形图? [关闭]

如何在现有数据库中创建 ASP.Net Identity 表?

在 ASP.NET MVC 3 中创建基于平台显示不同视图的自定义 ViewResult