如何处理ASP.NET MVC表单中的复选框?


246

警告:这个问题已有九年历史了!

最好的选择是搜索较新的问题,或者搜索下面的答案以查找您的MVC的特定版本,因为此处的许多答案已经过时了。

如果找到适合您版本的答案,请确保答案包含您正在使用的MVC的版本。
(原始问题从下面开始)


对我来说,这似乎有些奇怪,但是据我所知,这就是您的做法。

我有一组对象,希望用户选择其中一个或多个。这对我来说是“带有复选框的表格”。我的对象没有“选择”的任何概念(它们是通过反序列化wcf调用而形成的基本POCO)。因此,我执行以下操作:

public class SampleObject{
  public Guid Id {get;set;}
  public string Name {get;set;}
}

在视图中:

<%
    using (Html.BeginForm())
    {
%>
  <%foreach (var o in ViewData.Model) {%>
    <%=Html.CheckBox(o.Id)%>&nbsp;<%= o.Name %>
  <%}%>
  <input type="submit" value="Submit" />
<%}%>

而且,在控制器中,这是查看用户检查哪些对象的唯一方法:

public ActionResult ThisLooksWeird(FormCollection result)
{
  var winnars = from x in result.AllKeys
          where result[x] != "false"
          select x;
  // yadda
}

首先,它非常怪异,其次,对于用户检查的那些项目,FormCollection将其值列出为“ true false”,而不仅仅是true。

显然,我缺少了一些东西。我认为这是基于以下思想构建的:使用UpdateModel()或通过ModelBinder 更新html表单中作用于集合中的对象。

但是我没有为此设置对象。这是否意味着这是唯一的方法?还有另一种方法吗?


2
其他人可能会发现此解决方案有用:stackoverflow.com/questions/3291501/…–
亚伦

Answers:


262

Html.CheckBox做的事情很奇怪-如果您在结果页面上查看源代码,则会看到<input type="hidden" />每个复选框旁边都有一个正在生成的消息,它解释了您为每个表单元素看到的“ true false”值。

试试这个,它肯定可以在ASP.NET MVC Beta上工作,因为我已经尝试过了。

将其放在视图中,而不使用Html.CheckBox():

<% using (Html.BeginForm("ShowData", "Home")) {  %>
  <% foreach (var o in ViewData.Model) { %>
    <input type="checkbox" name="selectedObjects" value="<%=o.Id%>">
    <%= o.Name %>
  <%}%>
  <input type="submit" value="Submit" />
<%}%>

您的复选框都称为selectedObjectsvalue每个复选框的均为相应对象的GUID。

然后发布到以下控制器操作(或类似的事情,代替Response.Write()做有用的事情)

public ActionResult ShowData(Guid[] selectedObjects) {
    foreach (Guid guid in selectedObjects) {
        Response.Write(guid.ToString());
    }
    Response.End();
    return (new EmptyResult());
}

本示例将只编写您选中的框的GUID。ASP.NET MVC将所选复选框的GUID值映射到Guid[] selectedObjects您的参数中,甚至将Request.Form集合中的字符串解析为实例化的GUID对象,我认为这很好。


对!这也是我必须为我的应用程序做的!
Adhip Gupta,

70
wtf。隐藏具有相同名称的输入字段作为控件。它的ViewState 2.0!
Simon_Weaver

3
这在1.0版本中也存在。查看@ andrea-balducci提交的答案,它为您提供了一种解决此问题的明智方法。如果未选中此复选框,则检索到的结果文本应为“ false false”-这是解决大脑死机的好方法...
Bryan Rehbein 2009年

77
惊讶吗 WTF?隐藏的输入与复选框具有相同的名称-如果未选中具有相同名称的复选框,则不会发布其值,而隐藏的值将被发布。浏览器第一次遇到命名元素时,它将使用该值,并忽略具有相同名称的所有其他元素。这保证了提交了一个值:如果选中该复选框,则为true(假设它位于隐藏元素的上方),如果未选中该复选框,则为false(忽略空的复选框,并且隐藏的元素变为后备)。真正的wtf是为什么没有其他人指出这一点的原因。
nerraga

19
@nerraga:您错了:具有相同名称的多个表单元素是有效的html;如果是这样,则所有元素都将发布,并且我不确定该顺序是否已实际定义(尽管实际上可能只是按页面顺序排列)。使用“假”一词作为值会产生误导,所以是的,这是WTF-更好,更容易误导的选择应该是“存在”之类的东西,或者是诸如破折号之类的毫无意义的标记。
伊蒙·纳邦

95

HtmlHelper添加了一个隐藏的输入,以通知控制器有关Unchecked状态的信息。因此要具有正确的检查状态:

bool bChecked = form[key].Contains("true");

1
这是解决此问题的最简单方法,这是我一直使用的方法。它允许您使用辅助方法并说明ASP.NET MVC的行为。
尼克·丹尼尔斯

8
..或在未检查的情况下:bool bChecked = form [key] .Equals(“ false”); 执行.Contains(“ false”)失败,因为true值为“ true,false”。
马克·罗宾逊

54

如果您想知道为什么要在其中放置与复选框相同名称的隐藏字段,原因如下:

来自源代码MVCBetaSource \ MVC \ src \ MvcFutures \ Mvc \ ButtonsAndLinkExtensions.cs的注释

渲染其他<input type="hidden".../>复选框。这解决了在请求中未发送未选中复选框的情况。通过发送隐藏的输入,可以知道提交请求时页面上是否存在该复选框。

我想在幕后他们需要了解这一点,以便绑定到控制器操作方法上的参数。然后,您可能会有一个三态布尔值(绑定到可为null的bool参数)。我还没有尝试过,但是我希望那是他们所做的。


4
是的,这在您有分页网格等并且您想取消选择某些业务对象中先前选择的项目的情况下非常方便。
RichardOD

49

您还应该使用,<label for="checkbox1">Checkbox 1</label>因为这样人们可以单击标签文本以及复选框本身。它的样式也更容易,并且至少在IE中,当您浏览页面的控件时,它将突出显示。

<%= Html.CheckBox("cbNewColors", true) %><label for="cbNewColors">New colors</label>

这不仅是“哦,我能做到”的事情。它显着增强了用户体验。即使不是所有用户都知道他们可以单击许多意愿的标签。


27

我很惊讶这些答案都没有为此使用内置的MVC功能。

在这里写了一篇有关此的博客文章,甚至实际上将标签链接到复选框。我使用EditorTemplate文件夹以一种干净且模块化的方式来完成此任务。

您将最终在EditorTemplate文件夹中得到一个新文件,如下所示:

@model SampleObject

@Html.CheckBoxFor(m => m.IsChecked)
@Html.HiddenFor(m => m.Id)
@Html.LabelFor(m => m.IsChecked, Model.Id)

在您的实际视图中,无需循环此代码,只需执行以下一行代码即可:

@Html.EditorFor(x => ViewData.Model)

请访问我的博客文章以获取更多详细信息。


1
谢谢!Everboyd仍然使用旧表格方式。当您提交时,您可以访问模型而无需所有这些collection []和request.form垃圾-这就是我想要的。+1和啤酒
Piotr Kula 2013年

2
这应该是该问题的最佳答案。非常简单,易于实现。
Johan Gunawan 2014年

在找到答案之前,我花了一些时间努力寻找一个优雅的解决方案。它已有数年历史,但在2016年仍然完全有效!如果在多个情况下使用,请使用内置的SelectListItem作为非常适合此类型的泛型类型
Phil

SampleObject是列表吗?例如:@ModelType List(Of Type)
JoshYates1980 '16

25

这就是我一直在做的。

视图:


<input type="checkbox" name="applyChanges" />

控制器:


var checkBox = Request.Form["applyChanges"];

if (checkBox == "on")
{
...
}

我发现Html。*辅助方法在某些情况下不是很有用,因此最好还是用纯旧的HTML来做。这是其中之一,想到的另一个是单选按钮。

编辑:这是在预览5,显然版本之间的YMMV。


1
我只想添加一个替代示例:Object.Property =!String.IsNullOrEmpty(Request.Form [“ NAME”]);
Gup3rSuR4c 2010年

如果未选中,则转到异常
Xulfee 2011年

10

他们似乎选择仅读取第一个值,因此,当选中此复选框时为“ true”,而仅包括隐藏值时为“ false”。可以使用以下代码轻松获取:

model.Property = collection["ElementId"].ToLower().StartsWith("true");

8

@Dylan Beattie很棒的发现!!!我非常感谢你 为了进一步扩展,该技术还可以与“视图模型”方法完美配合。MVC非常酷,它足够聪明,可以通过绑定到View的Model对象的相同名称将Guid数组绑定到属性。例:

ViewModel:

public class SampleViewModel
{
    public IList<SampleObject> SampleObjectList { get; set; }
    public Guid[] SelectedObjectIds { get; set; }

    public class SampleObject
    {
        public Guid Id { get; set; }
        public string Name { get; set; }
    }
}

视图:

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Sample View</h2>
<table>
    <thead> 
        <tr>
            <th>Checked</th>
            <th>Object Name</th>
        </tr>
    </thead> 
<% using (Html.BeginForm()) %>
<%{%>                    
    <tbody>
        <% foreach (var item in Model.SampleObjectList)
           { %>
            <tr>
                <td><input type="checkbox" name="SelectedObjectIds" value="<%= item.Id%>" /></td>
                <td><%= Html.Encode(item.Name)%></td>
            </tr>
        <% } %>
    </tbody>
</table>
<input type="submit" value="Submit" />
<%}%>                    

控制器:

    [AcceptVerbs(HttpVerbs.Get)]
    public ActionResult SampleView(Guid id)
    {
        //Object to pass any input objects to the View Model Builder 
        BuilderIO viewModelBuilderInput = new BuilderIO();

        //The View Model Builder is a conglomerate of repositories and methods used to Construct a View Model out of Business Objects
        SampleViewModel viewModel = sampleViewModelBuilder.Build(viewModelBuilderInput);

        return View("SampleView", viewModel);
    }

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult SampleView(SampleViewModel viewModel)
    {
        // The array of Guids successfully bound to the SelectedObjectIds property of the View Model!
        return View();
    }

任何熟悉View Model哲学的人都会为之高兴,这就像冠军!


谢谢,您的SampleViewModel消除了原始答案中的一些混乱。
议会

6

我还想指出,您可以为每个复选框命名一个不同的名称,并将该名称作为actionresults参数的一部分。

例,

视图:

 <%= Html.CheckBox("Rs232CheckBox", false, new { @id = "rs232" })%>RS-232

 <%= Html.CheckBox("Rs422CheckBox", false, new { @id = "rs422" })%>RS-422

控制器:

public ActionResults MyAction(bool Rs232CheckBox, bool Rs422CheckBox) {
    ...
}

由于名称相同,因此视图中的值将传递给操作。

我知道此解决方案对于您的项目而言并不理想,但我想我会把这个想法抛诸脑后。


5
<input type = "checkbox" name = "checkbox1" /> <label> Check to say hi.</label>

从控制器:

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Index(FormCollection fc)
    {

         var s = fc["checkbox1"];

         if (s == "on")
         {
             string x = "Hi";
         }
    }

4

此问题也在1.0版中发生。Html.Checkbox()导致另一个隐藏字段被添加,其名称/ id与原始复选框相同。而且,当我尝试使用document.GetElemtentsByName()加载复选框数组时,您可以猜测情况如何变得混乱。真奇怪


4

据我所知,模型不想猜测是否为checked = true或false,我通过在提交表单之前使用jQuery在checkbox元素上设置value属性来解决此问题:

 $('input[type="checkbox"]').each(function () {
       $(this).attr('value', $(this).is(':checked'));
 }); 

这样,您不需要仅隐藏元素即可存储复选框的值。


4

我知道这个问题是在MVC3尚未发布时编写的,但是对于任何遇到此问题并正在使用MVC3的人,您可能希望使用“正确”的方式来执行此操作。

虽然我认为整个过程

Contains("true");

事情是一件很干净的事情,并且可以在所有MVC版本上使用,但问题是它没有考虑到文化(就布尔而言确实很重要)。

至少在MVC3中,计算布尔值的“正确”方法是使用ValueProvider。

var value = (bool)ValueProvider.GetValue("key").ConvertTo(typeof(bool));

当我编辑权限时,我在客户的一个站点中执行此操作:

var allPermissionsBase = Request.Params.AllKeys.Where(x => x.Contains("permission_")).ToList();
var allPermissions = new List<KeyValuePair<int, bool>>();

foreach (var key in allPermissionsBase)
{
     // Try to parse the key as int
     int keyAsInt;
     int.TryParse(key.Replace("permission_", ""), out keyAsInt);

     // Try to get the value as bool
     var value = (bool)ValueProvider.GetValue(key).ConvertTo(typeof(bool));
}

现在,它的优点在于您几乎可以将其与任何简单类型一起使用,并且根据文化(它会考虑金钱,小数等),它甚至是正确的。

当您形成如下所示的动作时,将使用ValueProvider:

public ActionResult UpdatePermissions(bool permission_1, bool permission_2)

但是,当您尝试动态构建这些列表并检查值时,您将永远在编译时都不知道ID,因此您必须即时对其进行处理。


您有理由使用Request.Params而不是向该方法添加FormCollection参数吗?
SwissCoder 2012年

没有理由,我看不出一种方法比另一种方法有任何好处。
Dan VanWinkle 2012年

1
抱歉,实际上是有原因的。只是看了一下我的代码,我将这个方法用于5个不同的调用,而且我不想从每个方法传递FormCollection。这是无需传递任何内容即可获取密钥的最简单方法。
Dan VanWinkle

是的,我是MVC的新手。我在某处读到,通常最好使用FormCollection而不是Request.Params,与使用类型化Model而不是FormCollection相同(因此,实际上最好使用模型,而避免一般使用Request.Params)。我注意到没有使用其他代码,例如allPermissions变量和keyAsInt。谢谢回答。
SwissCoder 2012年

3

最简单的方法是...

您设置名称和值。

<input type="checkbox" name="selectedProducts" value="@item.ProductId" />@item.Name

然后在提交时,抓住复选框的值并将其保存在一个int数组中。然后使用适当的LinQ函数。而已..

[HttpPost]
        public ActionResult Checkbox(int[] selectedObjects)
        {
            var selected = from x in selectedObjects
                           from y in db
                           where y.ObjectId == x
                           select y;                   

            return View(selected);
        }

3

与nautic20的答案相同,只需简单地使用MVC默认模型绑定复选框列表,其名称与ViewModel中string / int / enum的collection属性相同。这就对了。

但是需要指出一个问题。在每个复选框组件中,不应在其中放置“ Id”,这会影响MVC模型绑定。

以下代码适用于模型绑定:

 <% foreach (var item in Model.SampleObjectList)
       { %>
        <tr>
            <td><input type="checkbox" name="SelectedObjectIds" value="<%= item.Id%>" /></td>
            <td><%= Html.Encode(item.Name)%></td>
        </tr>
 <% } %>

以下代码不会绑定到模型(不同之处在于,为每个复选框分配了ID)

<% foreach (var item in Model.SampleObjectList)
       { %>
        <tr>
            <td><input type="checkbox" name="SelectedObjectIds" id="[some unique key]" value="<%= item.Id%>" /></td>
            <td><%= Html.Encode(item.Name)%></td>
        </tr>
<% } %>

谢谢回答,但这个问题是juuuust有点老了。大约六岁。您可能需要编辑并指定要使用的MVC版本。这将帮助使用较新版本的任何人找到此答案。

我同意那个。在头痛和咬牙切齿之后,删除唯一ID解决了此问题
Ody 2015年

我正在使用的MVC版本是.net MVC 4.0。
ChinaHelloWorld 2015年

2

这是我在使用Html.CheckBox(...

Replace("true,false","true").Split(',')

带有4个已选中,未选中,未选中,已选中的框,它将变为true,false,false,false,true,false变为true,false,false,true。我所需要的


0

这样的事情怎么样?

bool isChecked = false;
if (Boolean.TryParse(Request.Form.GetValues(”chkHuman”)[0], out isChecked) == false)
    ModelState.AddModelError(”chkHuman”, Nice try.”);

0

使用复选框HtmlHelper时,我更喜欢将发布的复选框表单数据作为数组使用。我真的不知道为什么,我知道其他方法也可以,但是我想我只想将逗号分隔的字符串尽可能地视为数组。

因此,进行“检查”或真实测试将是:

//looking for [true],[false]
bool isChecked = form.GetValues(key).Contains("true"); 

进行错误检查将是:

//looking for [false],[false] or [false]
bool isNotChecked = !form.GetValues(key).Contains("true"); 

主要区别是使用GetValues它作为数组返回。


0

只需在$(document).ready

$('input:hidden').each(function(el) {
    var that = $(this)[0];
    if(that.id.length < 1 ) {

        console.log(that.id);
        that.parentElement.removeChild(that);

    }
});

2
不幸的是,对于关闭了JavaScript的人(NoScript插件,旧手机,Lynx ...),您可能会在服务器端得到奇怪的结果
ArIck 2011年

0

我的解决方案是:

<input type="checkbox"  id="IsNew-checkbox"  checked="checked" />     
<input type="hidden"  id="IsNew" name="IsNew" value="true"  />      
<script language="javascript" type="text/javascript" >     
  $('#IsNew-checkbox').click(function () {    
      if ($('#IsNew-checkbox').is(':checked')) {    
          $('#IsNew').val('true');    
      } else {    
          $('#IsNew').val('false');    
       }    
  });   
</script>  

您可以在这里找到更多信息:http : //www.blog.mieten.pl/2010/12/asp-net-mvc-custom-checkbox-as-solution-of-string-was-not-recognized-as-a-有效布尔值/


您不需要为此使用任何Javascript ... var isChecked = formData [key] .Contains(“ true”);
Jammer

0

我遇到了几乎相同的问题,但控制器的返回值被其他值阻塞。

找到了一个简单的解决方案,但看起来有些粗糙。

尝试输入 Viewbag.您的Controller,现在给它起一个类似的名称Viewbag.Checkbool

现在切换到视图并尝试 @Viewbag.Checkbool使用它,您将获得控制器的值。

我的控制器参数如下所示:

public ActionResult Anzeigen(int productid = 90, bool islive = true)

并且我的复选框将像这样更新:

<input id="isLive" type="checkbox" checked="@ViewBag.Value" ONCLICK="window.location.href = '/MixCategory/Anzeigen?isLive=' + isLive.checked.toString()" />

0

使用@mmacaulay,我想到了这个用于布尔:

// MVC Work around for checkboxes.
bool active = (Request.Form["active"] == "on");

如果选中active = true

如果未选中激活=否

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.