MVC中模型映射到可空布尔值。

13

有一个包含该字段的视图模型:

public bool? IsDefault { get; set; }

在视图中尝试映射时,我遇到了一个错误:

<%= Html.CheckBoxFor(model => model.IsDefault) %>

无法将类型为 "bool?" 的值隐式转换为 "bool"。明确的转换存在(是否缺少强制转换?)

我已经尝试了强制转换和使用 .Value,但都没有成功。

请注意,我希望提交表单时将模型中的 IsDefault 设置为true或false。 值为null仅表示未填充模型。


你为什么需要检查模型是否已经填充?也许有另一种方式,一种正确的方式,来完成你需要做的事情? - Alex
可能是为什么CheckBoxFor会产生运行时错误的重复问题。 - Michael Maddox
6个回答

15

问题在于实际上有三种可能的值:true,false和null,因此CheckBoxFor不能处理三种状态(仅两种状态)。

Brad Wilson在他的博客这里讨论了这个问题。他使用DropDownList作为可空布尔值的解决方案。

这个StackOverflow上的问题比我上面描述的更好地描述了这种情况。解决方案的缺点是,有时可空并不意味着false,它应该是可空的。例如,在你不想应用true或false的过滤条件中。


8
如果您不关心空值,并且只希望在其为空时未选中复选框,则可以执行以下操作:
请在您的模型中创建另一个类型为bool的属性,如下所示:
public bool NotNullableBool
{
    get
    {
        return NullableBool == true;
    }
    set
    {
        NullableBool = value;
    }
}

那就直接将其用于绑定即可...

1
获取 { return NullableBool == true; } - vbullinger
1
这对我非常有效,然后将我的CheckboxFor绑定到我的NotNullableBool。 - Alicia

4
对我来说,这样更好:
<%= Html.CheckBox("IsDefault", Model.IsDefault.HasValue? Model.IsDefault : false) %>

1
这对于True / False来说是可以的,但如果你想处理一个真正的bool?,你也需要处理Null(将其视为Yes,No和Unknown)。 - Greg
2
通常情况下是这样的。但有时人们想知道已知真实、已知虚假和未提供/未知之间的区别。我们有像Married这样的字段。但我们想知道它们确实被选择为已婚、未婚或者数据没有输入。如果多个人处理记录,那么下一个人可能会问这个问题是否曾经被问过。但如果你只显示为false,人们会认为它已经被问过并返回了false。 - Greg
@MarkWorrall “我们”是我的开发团队和我们的客户,因为我们掌握了他们的需求。您可以在上面的代码中看到,如果Model.IsDefault.HasValue没有值,则会为false。你难道不应该只关心“积极”的匹配吗?如果不是那样,或者没有匹配任何内容,那么你知道它不是“积极”的一侧吗?使用格雷格的“已婚”示例-一个人要么已婚,要么没有。如果他们没有结婚,或者没有输入数据,谁在意呢?我们只是把他们当作没有结婚的人。如果您需要知道单个状态,您需要一个单选按钮,而不是一个T / F。 - vapcguy
只需将它们视为 - vapcguy
@Wade,我认为你不能说“Null表示该人从未被问过这个问题”,因为他们在表格上看到了它!如果您需要一个“N/A”选项,那么您需要一个单选按钮,并且必须回答它,而不是一个T/F。 - vapcguy
显示剩余6条评论

1
以下是如何将可空布尔型属性bool?映射到DropDownListFor的方法:
@model SomeModel

<!-- ...some HTML... -->

@Html.DropDownListFor(m => m.NullableBooleanProperty, new SelectList(
        new[] { 
            new { Value = "", Text = "-- Choose YES or NO --" },
            new { Value = "true", Text = "YES" },
            new { Value = "false", Text = "NO" },
        },
        "Value",
        "Text"
    ))

这里介绍如何通过使用非空代理属性作为解决方法将其映射到CheckBoxFor。请注意保留HTML标记。
在ViewModel中:
public bool NullableBooleanPropertyProxy
{
    get
    {
        return NullableBooleanProperty == true;
    }
    set
    {
        NullableBooleanProperty = value;
    }
}

在视图中:
@model SomeModel

<!-- ...some HTML... -->

@Html.CheckBoxFor(m => m.NullableBooleanPropertyProxy)

这种解决方法唯一的缺点是将null值视为false:如果您无法接受这一点,最好使用支持三种状态的控件,比如前面提到的DropDownListFor。欲了解更多信息,请阅读我博客上的this post

0

补充vapcguy的答案,另一种更加“简洁”的方法如下:

@Html.CheckBox("IsDefault", Model?.IsDefault)

或者

<%= Html.CheckBox("IsDefault", Model?.IsDefault) %>

0

您可以创建一个编辑器模板来呈现可空布尔值的复选框。将模板命名为Boolean.cshtml,以便在站点中的所有布尔属性中使用它作为默认模板。确保文件位于~/Views/Shared/EditorTemplates文件夹中。

@model bool?
@Html.CheckBox(String.Empty, Model??false)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接