129

我正在开发一个 ASP.NET MVC 4 应用程序。这个应用程序有一个基本的形式。我的表单模型如下所示:

public class MyModel
{
    public string Name { get; set; }
    public bool Remember { get; set; }
}

在我的表单中,我有以下 HTML。

<input id="Name" name="Name" type="text" value="@Model.Name" />
<input id="Remember" name="Remember" type="checkbox" value="@Model.Remember" />
<label for="Remember">&nbsp;Remember Me?</label>

当我发布表单时,模型中的 Remember 值始终为 false。但是,模型中的 Name 属性有一个值。我通过在以下设置断点对此进行了测试:

[HttpPost]
public ActionResult MyAction(MyModel model)
{
  Console.WriteLine(model.Remember.ToString());
}

我想不通。为什么没有设置 Checkbox 值?

4

19 回答 19

226
@Html.EditorFor(x => x.Remember)

会产生:

<input id="Remember" type="checkbox" value="true" name="Remember" />
<input type="hidden" value="false" name="Remember" />

它是如何工作的:

  • 如果checkbox保持未选中状态,则表单仅提交hidden值 (false)
  • 如果选中,则表单提交两个字段(false 和 true)和 true模型bool属性的 MVC 集

<input id="Remember" name="Remember" type="checkbox" value="@Model.Remember" />

如果选中,这将始终发送默认值。

于 2013-02-06T14:33:39.300 回答
73

由于您使用 Model.Name 来设置值。我假设您将一个空视图模型传递给视图。

因此,Remember 的值为 false,并将复选框元素上的值设置为 false。这意味着当您随后选择复选框时,您将在表单中发布值“false”。当你不选择它时,它不会被发布,所以模型默认为 false。这就是为什么您在这两种情况下都看到错误值的原因。

仅当您选中选择框时才会传递该值。要在 Mvc 中使用复选框

@Html.CheckBoxFor(x => x.Remember)

或者如果您不想将模型绑定到视图。

@Html.CheckBox("Remember")

Mvc 使用隐藏字段做了一些魔术,以在未选择时保留值。

编辑,如果你真的不喜欢这样做并且想自己生成元素,你可以这样做。

<input id="Remember" name="Remember" type="checkbox" value="true" @(Model.Remember ? "checked=\"checked\"" : "") />
于 2013-02-06T14:03:25.663 回答
15

只用这个

$("input[type=checkbox]").change(function () {
    if ($(this).prop("checked")) {
        $(this).val(true);
    } else {
        $(this).val(false);
    }
});
于 2017-03-19T21:21:04.647 回答
5

代替

 <input id="Remember" name="Remember" type="checkbox" value="@Model.Remember" />

采用:

 @Html.EditorFor(x => x.Remember)

这将为您提供一个专门用于记住的复选框

于 2013-02-06T13:54:53.837 回答
4

好的,复选框有点奇怪。当您使用 Html 助手时,它会在标记上生成两个复选框输入,如果选中,它们都会作为 IEnumerable 的名称-值对传入。

如果没有在标记上检查它,它只会传入值为 false 的隐藏输入。

因此,例如在您拥有的标记上:

      @Html.CheckBox("Chbxs") 

在控制器操作中(确保名称与控制器上的复选框参数名称匹配):

      public ActionResult Index(string param1, string param2,
      string param3, IEnumerable<bool> Chbxs)

然后在控制器中,您可以执行以下操作:

      if (Chbxs != null && Chbxs.Count() == 2)
        {
            checkBoxOnMarkup = true;
        }
        else
        {
            checkBoxOnMarkup = false;
        }

我知道这不是一个优雅的解决方案。希望这里有人可以指点一下。

于 2014-01-26T07:11:07.093 回答
3

要将表单中的复选框返回的值转换为布尔属性,我在自定义 ModelBinder 中使用了 ValueProviderResult 的构建转换器。

ValueProviderResult cbValue = bindingContext.ValueProvider.GetValue("CheckBoxName");
bool value = (bool)cbValue.ConvertTo(typeof(bool));
于 2014-10-02T16:00:22.757 回答
3

如果你真的想使用纯 HTML(无论出于何种原因)而不是内置的 HtmlHelper 扩展,你可以这样做。

代替

<input id="Remember" name="Remember" type="checkbox" value="@Model.Remember" />

尝试使用

<input id="Remember" name="Remember" type="checkbox" value="true" @(Model.Remember ? "checked" : "") />

HTML 中的复选框输入工作,因此当它们被选中时,它们发送值,当它们未被选中时,它们根本不发送任何东西(这将导致 ASP.NET MVC 回退到场,false)。此外,HTML 中复选框的值可以是任何东西,而不仅仅是真/假,所以如果你真的想要,你甚至可以在模型中为字符串字段使用复选框。

如果您使用内置的Html.RenderCheckbox,它实际上会输出两个输入:复选框和一个隐藏字段,以便在未选中复选框时发送一​​个错误值(不仅仅是什么都没有)。这可能会导致一些意外情况,例如:

于 2018-02-08T14:31:37.377 回答
3

如果使用 FormCollection 而不是模型,分配可以很简单:

MyModel.Remember = fields["Remember"] != "false";
于 2018-08-09T14:23:43.640 回答
2

我遇到了类似的问题,并且能够通过使用复选框、hiddenfor 和 little JQuery 来获取复选框值,如下所示:

@Html.CheckBox("isPreferred", Model.IsPreferred)
@Html.HiddenFor(m => m.IsPreferred)

<script>

    $("#isPreferred").change(function () {

        $("#IsPreferred").val($("#isPreferred").val());

    })

</script>
于 2014-12-01T22:07:15.037 回答
2

这是一个很大的痛苦,感觉应该更简单。这是我的设置和解决方案。

我正在使用以下 HTML 帮助程序:

@Html.CheckBoxFor(model => model.ActiveFlag)

然后,在控制器中,我正在检查表单收集和相应的处理:

bool activeFlag = collection["ActiveFlag"] == "false" ? false : true;
[modelObject].ActiveFlag = activeFlag;
于 2016-10-19T15:07:39.283 回答
1

我刚遇到这个(我不敢相信它不会开/关!)

无论如何!

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

将发布“on”或“off”的值。

不会绑定到布尔值,但你可以做这个愚蠢的解决方法!

 public class MyViewModel
 {
     /// <summary>
     /// This is a really dumb hack, because the form post sends "on" / "off"
     /// </summary>                    
     public enum Checkbox
     {
        on = 1,
        off = 0
     }
     public string Name { get; set; }
     public Checkbox Checked { get; set; }
}
于 2015-01-28T22:12:39.037 回答
1
@Html.EditorFor(x => x.ShowComment)


$(function () {
        // set default value to control on document ready instead of 'on'/'off' 
        $("input[type='checkbox'][name='ShowComment']").val(@Model.ShowComment.ToString().ToLower());
    });

    $("#ShowComment").change(function() {
        // this block sets value to checkbox control for "true" / "false"

        var chkVal = $("input[type='checkbox'][name='ShowComment']").val();
        if (chkVal == 'false') $("input[type='checkbox'][name='ShowComment']").val(true);
        else $("input[type='checkbox'][name='ShowComment']").val(false);

    });
于 2015-02-02T16:10:24.993 回答
1

对于使用模型的 MVC。模型:

public class UserInfo
{
    public string UserID { get; set; }
    public string UserName { get; set; }
    public string Password { get; set; }
    public bool RememberMe { get; set; }
}

HTML:

<input type="checkbox" value="true" id="checkbox1" name="RememberMe" checked="@Model.RememberMe"/>
<label for="checkbox1"></label>

在 [HttpPost] 函数中,我们可以得到它的属性。

[HttpPost]
public ActionResult Login(UserInfo user)
{
   //...
   return View(user);
}
于 2017-12-06T02:23:50.230 回答
0

对于具有相同名称的多个复选框...删除不必要的代码的代码 false :

List<string> d_taxe1 = new List<string>(Request.Form.GetValues("taxe1"));
d_taxe1 = form_checkbox.RemoveExtraFalseFromCheckbox(d_taxe1);

功能

public class form_checkbox
{

    public static List<string> RemoveExtraFalseFromCheckbox(List<string> val)
    {
        List<string> d_taxe1_list = new List<string>(val);

        int y = 0;

        foreach (string cbox in val)
        {

            if (val[y] == "false")
            {
                if (y > 0)
                {
                    if (val[y - 1] == "true")
                    {
                        d_taxe1_list[y] = "remove";
                    }
                }

            }

            y++;
        }

        val = new List<string>(d_taxe1_list);

        foreach (var del in d_taxe1_list)
            if (del == "remove") val.Remove(del);

        return val;

    }      



}

用它 :

int x = 0;
foreach (var detail in d_prix){
factured.taxe1 = (d_taxe1[x] == "true") ? true : false;
x++;
}
于 2015-05-19T16:02:11.517 回答
0
public ActionResult Index(string username, string password, string rememberMe)
{
   if (!string.IsNullOrEmpty(username))
   {
      bool remember = bool.Parse(rememberMe);
      //...
   }
   return View();
}
于 2015-06-14T12:50:27.420 回答
0

修改记住这样

public class MyModel
{
    public string Name { get; set; }
    public bool? Remember { get; set; }
}

在控制器中使用可为空的 bool 并在 null 上回退到 false 像这样

[HttpPost]
public ActionResult MyAction(MyModel model)
{
    model.Remember = model.Remember ?? false;
    Console.WriteLine(model.Remember.ToString());
}
于 2016-12-19T07:55:36.227 回答
0

就我而言,我没有在 get 方法中设置模型属性“Remember”。检查控制器中的逻辑。你可能也在做同样的事情。我希望这有帮助!

于 2017-11-07T04:41:56.223 回答
0

我通读了其他答案,但并没有完全让它发挥作用——所以这就是我最终得到的解决方案。

我的表单使用Html.EditorFor(e => e.Property)生成复选框,并FormCollection在控制器中使用,这将在控制器中传递一个字符串值'true,false'

当我处理结果时,我使用一个循环来循环它们——我还使用一个InfoProperty实例来表示从表单评估的当前模型值。

因此,我只是检查返回的字符串是否以单词开头'true',然后设置一个布尔变量true并将其传递给返回模型。

if (KeyName.EndsWith("OnOff"))
{
    // set on/off flags value to the model instance
    bool keyTrueFalse = false;
    if(values[KeyName].StartsWith("true"))
    {
        keyTrueFalse = true;
    }
    infoProperty.SetValue(processedInfo, keyTrueFalse);
}
于 2018-04-12T13:44:25.467 回答
0

疯狂的想法...当传递给模型中的布尔值时,Asp.Net MVC 应该只接受选中的复选框为“真”...。

我认为下面的——ModelBinder 接受 HTML 标准“on”表示真——应该一直是 Asp.Net MVC 中的默认实现。此解决方案适用于 Classic/Non-Core,但应该很容易适应 Core。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc;

namespace Brass9.Web.Mvc.ModelBinders
{
    public class FixedCheckboxFormModelBinder : System.Web.Mvc.IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            if (
                // Form POST
                !controllerContext.HttpContext.Request.ContentType.StartsWith
                    ("application/x-www-form-urlencoded", StringComparison.OrdinalIgnoreCase)
                /*
                // Note: This is implied - by the way we add this ModelBinder to the global app list (typeof(bool))
                ||
                bindingContext.ModelMetadata.ModelType != typeof(bool)
                */
            )
            {
                return null;
            }

            string name = bindingContext.ModelName;
            var valueProviderResult = bindingContext.ValueProvider.GetValue(name);

            if (valueProviderResult.AttemptedValue == "on")
            {
                var replacementResult = new ValueProviderResult(true, "on", System.Globalization.CultureInfo.CurrentCulture);
                bindingContext.ModelState.SetModelValue(name, replacementResult);
                return true;
            }

            return null;
        }
    }
}

然后在 Global.asax.cs 中启用它Application_Start()

ModelBinders.Binders.Add(typeof(bool), new Brass9.Web.Mvc.ModelBinders.FixedCheckboxFormModelBinder());

所以,我们只是构建了一个自定义的 ModelBinder,只过滤模型值,期望从 POST 表单中传入一个布尔值,然后将 HTML 标准“打开”传递给我们——安全地将其干预限制为复选框。

尝试应用此修复程序实际上有点奇怪,因为大多数关于 ModelBinders 的文档都是赞扬的,几乎没有明确的操作方法。

为什么我们以这种方式解决它:

我们正在迁移旧应用程序以完全使用原始 Asp.Net MVC(非核心)。不仅将所有复选框移动到@Html.Checkbox...(很多不是这样写的)需要很长时间,而且还会产生很多不良结果,因为额外的、不必要的隐藏输入以及迁移页面的困难。例如,我们知道有些页面有 Javascript 以特定顺序遍历 DOM 预期元素,隐藏的输入会中断,并且不想梳理每个页面以查找这些错误。

于 2021-10-05T02:19:24.610 回答