ASP.NET MVC 复选框组

Posted

技术标签:

【中文标题】ASP.NET MVC 复选框组【英文标题】:ASP.NET MVC Checkbox Group 【发布时间】:2011-01-05 06:48:36 【问题描述】:

我正在尝试为 ASP.NET MVC 中缺少“复选框组”制定解决方法。实现这一点的典型方法是使用同名的复选框,每个复选框都有它所代表的值。

<input type="checkbox" name="n" value=1 />
<input type="checkbox" name="n" value=2 />
<input type="checkbox" name="n" value=3 />

提交时,它将用逗号分隔请求项“n”的所有值。因此,如果在提交时检查了所有三个,则 Request["n"] == "1,2,3"。在 ASP.NET MVC 中,您可以将参数 n 作为数组来接受这篇文章。

public ActionResult ActionName( int[] n )  ... 

以上所有方法都可以正常工作。我遇到的问题是,当验证失败时,复选框不会恢复为选中状态。任何建议。

问题代码:(我从默认的asp.net mvc项目开始)

控制器

    public class HomeController : Controller
    
        public ActionResult Index()
           var t = getTestModel("First");
            return View(t);
        

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Index(TestModelView t)
           if(String.IsNullOrEmpty( t.TextBoxValue))
                ModelState.AddModelError("TextBoxValue", "TextBoxValue required.");
            var newView = getTestModel("Next");
            return View(newView);
        

        private TestModelView getTestModel(string prefix)
           var t = new TestModelView();
            t.Checkboxes = new List<CheckboxInfo>()
               new CheckboxInfo()Text = prefix + "1", Value="1", IsChecked=false,
                new CheckboxInfo()Text = prefix + "2", Value="2", IsChecked=false 
            ;
            return t;
        
    
    public class TestModelView
       public string TextBoxValue  get; set; 
        public List<CheckboxInfo> Checkboxes  get; set; 
    
    public class CheckboxInfo
       public string Text  get; set; 
        public string Value  get; set; 
        public bool IsChecked  get; set; 
    

ASPX

<%
using( html.BeginForm() ) 
%>  <p><%= Html.ValidationSummary() %></p>
    <p><%= Html.TextBox("TextBoxValue")%></p>
    <p><%  
    int i = 0;
    foreach (var cb in Model.Checkboxes)
     %>
        <input type="checkbox" name="Checkboxes[<%=i%>]" 
            value="<%= Html.Encode(cb.Value) %>" <%=cb.IsChecked ? "checked=\"checked\"" : String.Empty %> 
            /><%= Html.Encode(cb.Text)%><br />
    <%      i++;
     %></p>
    <p><input type="submit" value="submit" /></p>
<%

%>

工作代码

控制器

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(TestModelView t)

    if(String.IsNullOrEmpty( t.TextBoxValue))
       ModelState.AddModelError("TextBoxValue", "TextBoxValue required.");
        return View(t); 
    
    var newView = getTestModel("Next");
    return View(newView);

ASPX

int i = 0;
foreach (var cb in Model.Checkboxes)
 %>
    <input type="checkbox" name="Checkboxes[<%=i%>].IsChecked" <%=cb.IsChecked ? "checked=\"checked\"" : String.Empty %> value="true" />
    <input type="hidden"   name="Checkboxes[<%=i%>].IsChecked" value="false" />
    <input type="hidden" name="Checkboxes[<%=i%>].Value" value="<%= cb.Value %>" />
    <input type="hidden" name="Checkboxes[<%=i%>].Text" value="<%= cb.Text %>" />
    <%= Html.Encode(cb.Text)%><br />
<%      i++;
 %></p>
<p><input type="submit" value="submit" /></p>

当然,也可以使用 Html Helpers 完成类似的操作,但这是可行的。

【问题讨论】:

发布控制器的代码。 正如他们在黑客帝国中所说的那样;没有状态;)***.com/questions/1473483/asp-net-mvc-and-viewstate @magnus:对于可能是控制器中的一个简单问题,这需要解决很多问题。 哦,但是有 ModelState... 只是有点不同。 @Robert 好吧,这不是一个答案,只是一些关于 mvc、modelstate 等的信息...... 【参考方案1】:

我不知道如何解决您的问题,但您可以使用以下代码定义您的复选框:

<%= Html.CheckBox("n[0]") %><%= Html.Hidden("n[0]",false) %>
<%= Html.CheckBox("n[1]") %><%= Html.Hidden("n[1]",false) %>
<%= Html.CheckBox("n[2]") %><%= Html.Hidden("n[2]",false) %>

需要隐藏字段,因为如果未选中复选框,则表单不会发送任何值。使用隐藏字段会发送错误消息。

您的发布方法将是:

[HttpPost]
public ActionResult Test(bool[] n)

    return View();

这可能不是最佳的,我对 cme​​ts 持开放态度,但它有效:)

编辑

加长版:

<%= Html.CheckBox("n[0].Checked") %><%= Html.Hidden("n[0].Value",32) %><%= Html.Hidden("n[0].Checked",false) %>
<%= Html.CheckBox("n[1].Checked") %><%= Html.Hidden("n[1].Value",55) %><%= Html.Hidden("n[1].Checked",false) %>
<%= Html.CheckBox("n[2].Checked") %><%= Html.Hidden("n[2].Value",76) %><%= Html.Hidden("n[2].Checked",false) %>

您的发布方法将是:

[HttpPost]
public ActionResult Test(CheckedValue[] n)

    return View();


public class CheckedValue

     public bool Checked  get; set; 
     public bool Value  get; set; 

我写的没有VS,所以可能需要一点修正。

【讨论】:

我可以做一些事情来达到这个效果,尽管我必须将它绑定到值列表。正如问题中的示例一样,我需要知道 [0] 是 1 或在实际情况下为 79 或其他。我想我可以通过将值列表存储为会话来处理。 宾果游戏!好想法。我忘记了几件事...... 1. 引用 .Value 和 2. 当数组的任何部分具有已发布的值时,活页夹将在该位置创建对象。如果你跳过一个索引,它不会创建任何超过跳过的索引。【参考方案2】:

看看最终的解决方案:

public static class Helpers

    public static string CheckboxGroup<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> propertySelector, int value) where TProperty: IEnumerable<int>
    
        var groupName = GetPropertyName(propertySelector);
        var modelValues = propertySelector.Compile().Invoke(htmlHelper.ViewData.Model);

        var svalue = value.ToString();
        var builder = new TagBuilder("input");
        builder.GenerateId(groupName);
        builder.Attributes.Add("type", "checkbox");
        builder.Attributes.Add("name", groupName);
        builder.Attributes.Add("value", svalue);
        var contextValues = HttpContext.Current.Request.Form.GetValues(groupName);
        if ((contextValues != null && contextValues.Contains(svalue)) || (modelValues != null && modelValues.Contains(value)))
        
            builder.Attributes.Add("checked", null);
        
        return builder.ToString(TagRenderMode.Normal);
    

    private static string GetPropertyName<T, TProperty>(Expression<Func<T, TProperty>> propertySelector)
    
        var body = propertySelector.Body.ToString();
        var firstIndex = body.IndexOf('.') + 1;
        return body.Substring(firstIndex);
    

在你看来:

                        <%= Html.CheckboxGroup(model => model.DocumentCoverCustom, "1")%>(iv),<br />
                        <%= Html.CheckboxGroup(model => model.DocumentCoverCustom, "2")%>(vi),<br />
                        <%= Html.CheckboxGroup(model => model.DocumentCoverCustom, "3")%>(vii),<br />
                        <%= Html.CheckboxGroup(model => model.DocumentCoverCustom, "4")%>(ix)<br />

【讨论】:

我知道这已经很老了,但是你应该像 mvc 中的其他 @Html 助手一样返回值 MvcHtmlString 而不是返回字符串。将 return builder.ToString(TagRenderMode.Normal); 替换为 return new MvcHtmlString(builder.ToString(TagRenderMode.SelfClosing)); 这将输出 html 并给出自关闭标签,因为输入通常是自关闭的。不过很好的解决方案!【参考方案3】:

嗯...复选框不会自己知道它们的状态,特别是如果您不使用 Html.CheckBox 帮助器(如果您使用,请参阅 LuKLed 的答案)。您必须将每个框的选中状态放入您的 ViewData(或模型)中,然后以一种或另一种方式在您的视图中执行查找。

警告:非常丑陋的概念验证代码:

控制器:

//validation fails
ViewData["checkboxn"] = n;
return View();

查看:

<% int[] n = (int[])ViewData["checkboxn"]; %>
<input type="checkbox" name="n" value=1 <%= n != null && n.Contains(1) ? "checked=\"checked\"" : "" %> />
<input type="checkbox" name="n" value=2 <%= n != null && n.Contains(2) ? "checked=\"checked\"" : "" %> />
<input type="checkbox" name="n" value=3 <%= n != null && n.Contains(3) ? "checked=\"checked\"" : "" %> />

我在这里所做的只是将数组 n 传递回视图,如果它包含相应复选框的值,则将 checked="checked" 添加到元素。

当然,您可能希望将其重构为您自己的 HtmlHelper,或者以其他方式使其不那么难看。

【讨论】:

【参考方案4】:

想要一种干净/简单的方法的人可能会对此解决方案感兴趣: Maintain state of a dynamic list of checkboxes in ASP.NET MVC

我不会真的推荐使用 Html.CheckBox 除非你有一个超级简单的、单一的复选框绑定到一个布尔值(或最多几个静态的)。当您开始在单个数组或动态复选框中拥有复选框列表时,很难使用它,并且您最终会在服务器端膨胀中对整个世界进行编程,只是为了处理不足之处并让一切正常工作。忘记它,只需使用上面以 HTML 为中心的干净解决方案,您就可以快速启动并运行,并且将来需要维护的麻烦更少。

【讨论】:

【参考方案5】:

我知道这肯定太晚了,但以防万一其他人发现自己在这里..

MVC 确实有办法处理复选框组。

在您的视图模型中:

[Display(Name = "接受哪些信用卡:")]

public string[] EmployeeRoles get;放;

在您的页面上:

            <input id="EmployeeRoles" name="EmployeeRoles" type="checkbox" value="Supervisor" 
            @(Model.EmployeeRoles != null && Model.EmployeeRoles.Contains("Supervisor") ? "checked=true" : string.Empty)/>
            &nbsp;<span>Supervisor</span><br />

            <input id="EmployeeRoles" name="EmployeeRoles" type="checkbox" value="Auditor" 
            @(Model.EmployeeRoles != null && Model.EmployeeRoles.Contains("Auditor") ? "checked=true" : string.Empty)/>
            &nbsp;<span>Auditor</span><br />

            <input id="EmployeeRoles" name="EmployeeRoles" type="checkbox" value="Administrator" 
            @(Model.EmployeeRoles != null && Model.EmployeeRoles.Contains("Administrator") ? "checked=true" : string.Empty) />
            &nbsp;<span>Administrator</span>

我非常努力地用剃刀而不是骰子来创建这些控件。它使 创建你们都提到的隐藏字段。对于您的复选框组 你不需要那个隐藏字段,只需要我上面添加的代码。您可以创建一个 html 帮助程序来为您创建此代码。

    public static HtmlString CheckboxGroup<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> propertySelector, Type EnumType)
    
        var groupName = GetPropertyName(propertySelector);
        var modelValues = ModelMetadata.FromLambdaExpression(propertySelector, htmlHelper.ViewData).Model;//propertySelector.Compile().Invoke(htmlHelper.ViewData.Model);

        StringBuilder literal = new StringBuilder();  

        foreach (var value in Enum.GetValues(EnumType))
        
            var svalue = value.ToString();
            var builder = new TagBuilder("input");
            builder.GenerateId(groupName);
            builder.Attributes.Add("type", "checkbox");
            builder.Attributes.Add("name", groupName);
            builder.Attributes.Add("value", svalue);
            var contextValues = HttpContext.Current.Request.Form.GetValues(groupName);
            if ((contextValues != null && contextValues.Contains(svalue)) || (modelValues != null && modelValues.ToString().Contains(svalue)))
            
                builder.Attributes.Add("checked", null);
            

            literal.Append(String.Format("</br>1&nbsp;<span>0</span>", svalue.Replace('_', ' '),builder.ToString(TagRenderMode.Normal)));
        

        return (HtmlString)htmlHelper.Raw(literal.ToString()); 
    

    private static string GetPropertyName<T, TProperty>(Expression<Func<T, TProperty>> propertySelector)
    
        var body = propertySelector.Body.ToString();
        var firstIndex = body.IndexOf('.') + 1;
        return body.Substring(firstIndex);
    

在您的页面上像这样使用它: @Html.CheckboxGroup(m => m.EmployeeRoles, typeof(Enums.EmployeeRoles))

我使用枚举,但你可以使用任何类型的集合

【讨论】:

以上是关于ASP.NET MVC 复选框组的主要内容,如果未能解决你的问题,请参考以下文章

单击复选框时 ASP.NET MVC 提交表单

如何在 Asp.NET MVC 中使用复选框创建多选下拉菜单

如何使用 DataAnnotations 处理 ASP.NET MVC 2 中的布尔值/复选框?

为啥复选框选择列表总是在 ASP.NET MVC-5 中发布为 null [重复]

如何在我的 ASP.NET MVC 应用程序中实现“全选”复选框?

asp.net mvc视图中的C#复选框事件不在表单内