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

发布于 2024-09-27 06:55:36 字数 259 浏览 4 评论 0原文

我知道 ASP.NET MVC Html 辅助扩展方法中有一个 ListBoxFor 扩展方法,但我一直认为复选框列表比列表框更用户友好。

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

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

I know there is a ListBoxFor extension method among the ASP.NET MVC Html helper extension methods, but I always thought that a checkbox list is more user-friendly than a list box.

There was a very convenient CheckBoxList control in good old WebForms, but obviously that is out of the picture now.

The question is, why is there no way in ASP.NET MVC to create a check box list? How can I write my own extension method that creates a check box list and behaves in a similar way ListBoxFor behaves?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

疑心病 2024-10-04 06:55:36

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

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

//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());
}

Here is a strongly typed HtmlHelper for CheckBoxListFor that handles selected items as an array in your viewdata model. I chose not to wrapper the Html.CheckBox or Html.CheckBoxFor methods as I don't want the hidden "false" fields in my checkbox lists.

Please feel free to improve on this and repost :-)

//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());
}
饭团 2024-10-04 06:55:36

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

        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());
    }

I'm still experimenting but this seems to get along with the default binder and persists the user selections after post.. Hidden fields, really?? .. will this fly in html5 ? This feels crazy but I'd rather do this than hit my db for drop down lists and checkbox lists just because ModelState.IsValid is false..

        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());
    }
十二 2024-10-04 06:55:36

虽然 Microsoft 员工可能是唯一能够回答为什么不存在这种辅助方法的人,但您可以尝试:

模型:

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 将处理所需的所有内容。

While Microsoft employees are probably the only ones that can answer why such helper method doesn't exist you could try:

Model:

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

Controller:

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);
    }
}

View:

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

As you can see EditorFor will handle everything that's needed.

后eg是否自 2024-10-04 06:55:36

您可能对 CheckBoxList 帮助程序感兴趣Jeremiah Clark 撰写的 MVC 文章(不幸的是,该文章的日期为 2008 年 11 月,涉及 MVC 1)。

You might be interested in CheckBoxList Helper for MVC article by Jeremiah Clark (unfortunately it's dated Nov 2008 and concerns MVC 1).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文