asp.net-mvc ASP.NET MVC 复选框组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2067786/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
ASP.NET MVC Checkbox Group
提问by Greg Ogle
I am trying to formulate a work-around for the lack of a "checkbox group" in ASP.NET MVC. The typical way to implement this is to have check boxes of the same name, each with the value it represents.
我正在尝试为 ASP.NET MVC 中缺少“复选框组”制定解决方法。实现这一点的典型方法是使用相同名称的复选框,每个复选框都有它所代表的值。
<input type="checkbox" name="n" value=1 />
<input type="checkbox" name="n" value=2 />
<input type="checkbox" name="n" value=3 />
When submitted, it will comma delimit all values to the request item "n".. so Request["n"] == "1,2,3" if all three are checked when submitted. In ASP.NET MVC, you can have a parameter of n as an array to accept this post.
提交时,它将以逗号分隔所有值到请求项“n”..所以 Request["n"] == "1,2,3" 如果在提交时所有三个都被选中。在 ASP.NET MVC 中,您可以将参数 n 作为数组来接受这篇文章。
public ActionResult ActionName( int[] n ) { ... }
All of the above works fine.The problem I have is that when validation fails, the check boxes are not restored to their checked state. Any suggestions.
以上所有工作正常。我遇到的问题是,当验证失败时,复选框不会恢复到选中状态。有什么建议。
Problem Code:(I started with the default asp.net mvc project)
问题代码:(我从默认的asp.net mvc项目开始)
Controller
控制器
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
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>
<%
}
%>
Working Code
工作代码
Controller
控制器
[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
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>
Of course something similar could be done with Html Helpers, but this works.
当然,类似的事情可以用 Html Helpers 来完成,但这是有效的。
采纳答案by LukLed
I don't know how to solve your problem, but you could define your checkboxes with this code:
我不知道如何解决您的问题,但您可以使用以下代码定义复选框:
<%= 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) %>
Hidden fields are needed, because if checkbox is not checked, form doesn't send any value. With hidden field it sends false.
需要隐藏字段,因为如果未选中复选框,则表单不会发送任何值。使用隐藏字段发送错误。
Your post method will be:
您的发布方法将是:
[HttpPost]
public ActionResult Test(bool[] n)
{
return View();
}
It may not be optimal and I am open to comments, but it works:)
它可能不是最佳的,我愿意接受评论,但它有效:)
EDIT
编辑
Extended version:
扩大的视野:
<%= 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) %>
Your post method will be:
您的发布方法将是:
[HttpPost]
public ActionResult Test(CheckedValue[] n)
{
return View();
}
public class CheckedValue
{
public bool Checked { get; set; }
public bool Value { get; set; }
}
I wrote it without VS, so it may need little correction.
我在没有 VS 的情况下写的,所以它可能需要一点修正。
回答by Hans
Behold the final solution:
看看最终的解决方案:
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);
}
}
And in your view:
在您看来:
<%= 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 />
回答by Aaron
This solution may be of interest to those wanting a clean/simple approach: Maintain state of a dynamic list of checkboxes in ASP.NET MVC
对于那些想要干净/简单方法的人来说,此解决方案可能会感兴趣: 在 ASP.NET MVC 中维护动态复选框列表的状态
I wouldn't really recommend the use of Html.CheckBox unless you have a super simple, single checkbox bound to a single bool (or a couple of static ones at most). When you start having lists of checkboxes in a single array or dynamic checkboxes, it is difficult to work with and you end up programming the whole world in server side bloat just to deal with the shortfalls and get everything working. Forget it, and just use the clean HTML focused solution above and you're up and running quickly with less mess to maintain in the future.
我真的不推荐使用 Html.CheckBox ,除非您有一个超级简单的单个复选框绑定到单个 bool (或最多几个静态复选框)。当您开始在单个数组或动态复选框中使用复选框列表时,很难使用,并且您最终会在服务器端膨胀中对整个世界进行编程,只是为了处理不足并使一切正常工作。忘记它,只需使用上面干净的以 HTML 为重点的解决方案,您就可以快速启动并运行,并且将来需要维护的混乱更少。
回答by Kurt Schindler
Well... the check boxes aren't going to know their state on their own, especially if you are not using the Html.CheckBox helper (if you are, see LuKLed's answer). You're going to have to put the checked state of each box in your ViewData (or Model) and then perform a look-up in your View in one way or another.
嗯......复选框不会自己知道它们的状态,特别是如果你没有使用 Html.CheckBox 助手(如果你是,请参阅 LuKLed 的答案)。您将不得不将每个框的选中状态放在 ViewData(或模型)中,然后以一种或另一种方式在您的视图中执行查找。
Warning: Really ugly proof-of-concept code:
警告:非常丑陋的概念验证代码:
Controller:
控制器:
//validation fails
ViewData["checkboxn"] = n;
return View();
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\"" : "" %> />
All I'm doing here is passing the array n back to the view, and if it contains a value for the respective checkbox, adding checked="checked"to the element.
我在这里所做的就是将数组 n 传递回视图,如果它包含相应复选框的值,则添加checked="checked"到元素中。
You would probably want to refactor this into an HtmlHelper of your own, or otherwise make this less ugly, of course.
当然,您可能希望将其重构为您自己的 HtmlHelper,或者以其他方式使其不那么难看。
回答by Charles McIntosh
I know this must be insanely late but just incase anyone else finds themselves here..
我知道这一定是太晚了,但以防万一其他人发现自己在这里..
MVC does have a way to handle checkbox groups.
MVC 确实有处理复选框组的方法。
in your view model:
在您的视图模型中:
[Display(Name = "Which Credit Cards are Accepted:")]
[Display(Name = "接受哪些信用卡:")]
public string[] EmployeeRoles{ get; set; }
公共字符串[] EmployeeRoles{ 获取;放; }
On your Page:
在您的主页上:
<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>
I tried very hard to create these controls with razor but no dice. It keeps creating that hidden field you all have referred to. for your checkbox group you don't need that hidden field, just the code I have added above. You can create an html helper to create this code for you.
我非常努力地用剃刀而不是骰子来创建这些控件。它一直在创建你们都提到的隐藏字段。对于您的复选框组,您不需要那个隐藏字段,只需要我在上面添加的代码。您可以创建一个 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);
}
on your page use it like so: @Html.CheckboxGroup(m => m.EmployeeRoles, typeof(Enums.EmployeeRoles))
在您的页面上像这样使用它:@Html.CheckboxGroup(m => m.EmployeeRoles, typeof(Enums.EmployeeRoles))
I use an enum but you can use any kind of collection
我使用枚举,但您可以使用任何类型的集合

