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

时间:2008-10-20 21:30:11

标签: asp.net-mvc forms checkbox

警告:这个问题超过九年了!

您最好的选择是搜索更新的问题,或搜索下面的答案,寻找您的特定版本的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。

显然,我错过了一些东西。我认为这是基于这样的想法构建的,即在html表单中作用的集合中的对象使用UpdateModel()或通过ModelBinder进行更新。

但我没有为此设置对象;这是否意味着这是唯一的方法?还有其他办法吗?

22 个答案:

答案 0 :(得分:262)

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

试试这个,这肯定适用于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" />
<%}%>

您的复选框全部称为selectedObjects,每个复选框的value都是相应对象的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对象,我认为这很不错。

答案 1 :(得分:95)

HtmlHelper添加隐藏输入以通知控制器有关未选中状态的信息。 所以要有正确的检查状态:

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

答案 2 :(得分:54)

如果您想知道为什么他们使用与复选框同名的隐藏字段,原因如下:

来自源代码的评论MVCBetaSource \ MVC \ src \ MvcFutures \ Mvc \ ButtonsAndLinkExtensions.cs

  

为复选框呈现额外的<input type="hidden".../>。   这解决了场景   未选中的复选框不会被发送   请求。发送隐藏的输入   让人有可能知道   复选框出现在页面上   请求已提交。

我想在幕后他们需要知道这个用于绑定控制器动作方法上的参数。然后,我可以使用三态布尔值(绑定到可以为空的bool参数)。我没试过,但我希望他们做了什么。

答案 3 :(得分:49)

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

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

这不仅仅是'哦,我能做到'的事情。它是一项重要的用户体验增强。即使并非所有用户都知道他们可以点击许多标签。

答案 4 :(得分:27)

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

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

您最终会在EditorTemplate文件夹中找到一个如下所示的新文件:

@model SampleObject

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

在你的实际视图中,没有必要循环这个,只需1行代码:

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

访问我的blog post了解详情。

答案 5 :(得分:25)

这就是我一直在做的事情。

查看:


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

控制器:


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

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

我发现Html。*帮助器方法在某些情况下不那么有用,而且我最好用普通的旧HTML做。这是其中之一,另一个想到的是单选按钮。

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

答案 6 :(得分:10)

他们似乎只选择读取第一个值,因此选中复选框时为“true”,而仅包含隐藏值时为“false”。这很容易用这样的代码获取:

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

答案 7 :(得分:8)

@Dylan Beattie很棒的发现!!!我非常感谢你为了进一步扩展,这种技术也适用于View Model方法。 MVC非常酷,它足够聪明,可以通过绑定到View的Model对象的相同名称将Guids数组绑定到属性。例如:

视图模型:

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理念的人都会高兴,这就像冠军一样!

答案 8 :(得分: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) {
    ...
}

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

我知道这个解决方案并不适合你的项目,但我想我会把这个想法抛在那里。

答案 9 :(得分:5)

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

来自Controller:

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

         var s = fc["checkbox1"];

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

答案 10 :(得分:4)

此问题也在1.0版本中发生。 Html.Checkbox()导致添加另一个隐藏字段,其名称/ ID与原始复选框相同。当我尝试使用document.GetElemtentsByName()加载一个复选框数组时,你可以猜出事情是如何搞砸的。这是一个奇怪的事情。

答案 11 :(得分:4)

我知道这个问题是在MVC3没有出来的时候编写的,但是对于那些提出这个问题且正在使用MVC3的人来说,你可能想要“正确”的方法来做到这一点。

虽然我认为做到了整个

Contains("true");
事情是伟大而干净的,适用于所有MVC版本,问题在于它没有考虑文化(就好像在布尔的情况下它真的很重要)。

至少在MVC3中,找出bool值的“正确”方法是使用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,因此您必须动态处理它们。

答案 12 :(得分:4)

从我可以收集的内容来看,模型不想猜测checked = true或false,我通过在jQuery上设置一个值属性来解决这个问题,然后再提交表格:

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

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

答案 13 :(得分:3)

与nautic20的答案相同,只需使用与ViewModel中string / int / enum的集合属性相同名称的MVC默认模型绑定复选框列表。就是这样。

但有一个问题需要指出。在每个复选框组件中,不应在其中放置“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>
<% } %>

答案 14 :(得分: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);
        }

答案 15 :(得分:2)

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

)时松开双值的方法
Replace("true,false","true").Split(',')

选中4个框,取消选中,取消选中,检查它是否已关闭 真的,假的,假的,假的,真的,假的 成 真的,假的,假的,真实的。 正是我需要的东西

答案 16 :(得分: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);

    }
});

答案 17 :(得分: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,因为它返回数组。

答案 18 :(得分: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-valid-boolean/

答案 19 :(得分:0)

这样的事情怎么样?

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

答案 20 :(得分:0)

我有几乎相同的问题,但我的控制器的返回值被其他值阻止。

找到一个简单的解决方案,但似乎有点粗糙。

尝试在您的控制器中输入Viewbag.,现在为其命名为Viewbag.Checkbool

现在切换到View并尝试使用此@Viewbag.Checkbool,您将获得Controller的值。

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

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

我的Checkbox会像这样更新:

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

答案 21 :(得分:0)

使用@mmacaulay,我为bool想出了这个:

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

如果选中 active = true

如果未选中 active = false