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();
这可能不是最佳的,我对 cmets 持开放态度,但它有效:)
编辑
加长版:
<%= 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)/>
<span>Supervisor</span><br />
<input id="EmployeeRoles" name="EmployeeRoles" type="checkbox" value="Auditor"
@(Model.EmployeeRoles != null && Model.EmployeeRoles.Contains("Auditor") ? "checked=true" : string.Empty)/>
<span>Auditor</span><br />
<input id="EmployeeRoles" name="EmployeeRoles" type="checkbox" value="Administrator"
@(Model.EmployeeRoles != null && Model.EmployeeRoles.Contains("Administrator") ? "checked=true" : string.Empty) />
<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 <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 中使用复选框创建多选下拉菜单
如何使用 DataAnnotations 处理 ASP.NET MVC 2 中的布尔值/复选框?
为啥复选框选择列表总是在 ASP.NET MVC-5 中发布为 null [重复]