代码之家  ›  专栏  ›  技术社区  ›  oglester

ASP.NET MVC复选框组

  •  12
  • oglester  · 技术社区  · 15 年前

    我正试图为ASP.NETMVC中缺少“复选框组”制定一个解决方案。实现这一点的典型方法是使用相同名称的复选框,每个复选框都具有它所表示的值。

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

    提交时,它将用逗号分隔请求项“n”的所有值。。因此,如果提交时三个选项都被选中,则请求[“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; }
        }
    }
    

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

    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>
    

    5 回复  |  直到 15 年前
        1
  •  6
  •   LukLed    15 年前

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

    <%= 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) %>
    

    需要隐藏字段,因为若未选中复选框,则表单不会发送任何值。在隐藏字段中,它发送false。

    您的post方法将是:

    [HttpPost]
    public ActionResult Test(bool[] n)
    {
        return View();
    }
    

    编辑

    扩展版本:

    <%= 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,所以可能需要很少的修改。

        2
  •  6
  •   Hans    15 年前

    看看最终的解决方案:

    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 />
    
        3
  •  1
  •   Elijah66    15 年前

    好。。。复选框本身不会知道它们的状态,特别是如果您没有使用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" 到元素。

        4
  •  1
  •   Community CDub    8 年前

    希望采用干净/简单方法的人可能会对该解决方案感兴趣: Maintain state of a dynamic list of checkboxes in ASP.NET MVC

        5
  •  0
  •   Charles McIntosh    9 年前

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

    在视图模型中:

    [显示(Name=“接受哪些信用卡:”)]

    公共字符串[]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);
        }
    

    在您的页面上,这样使用它:

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