可空布尔值的复选框


97

我的模型有一个布尔值,必须为空

public bool? Foo
{
   get;
   set;
}

所以在我的剃刀cshtml中

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

除了那行不通。也不会使用(bool)对其进行强制转换。如果我做

@Html.CheckBoxFor(m => m.Foo.Value)

不会产生错误,但是在发布且foo设置为null时不会绑定到我的模型。在页面上显示Foo并将其绑定到帖子上的模型的最佳方法是什么?



2
该线程忽略了这个问题,我必须能够将null检测为第三个值。未选中复选框的表单提交和未显示复选框的表单提交是必须解决的两种不同情况。
DMulligan 2011年

Answers:


107

我知道了

@Html.EditorFor(model => model.Foo) 

然后在我的EditorTemplates文件夹中制作一个Boolean.cshtml并粘贴

@model bool?

@Html.CheckBox("", Model.GetValueOrDefault())

内。


2
为我工作。谢谢!
塞缪尔

1
在使用可空布尔类型时,我使用了这个'''@ Html.CheckBoxFor(m => m.Foo.HasValue)'''
Gaurav Aroraa 2014年

9
@GauravKumarArora您正在为可为空的HasValue属性创建一个复选框,而不是实际的布尔值。无论基础值是多少,都会创建一个选中的复选框。如果可为空的值,则它将始终为true。
Siewers

1
无疑,这是此页面上非常干净和灵活的解决方案。+1
T恤2015年

2
只是一个注释:1.您必须将该文件存储在“视图/共享/ EditorTemplates”中2.您必须将此文件命名为“ Boolean.cshtml”
Jarrette

46

在类似的问题(将Nullable Bool渲染为CheckBox)中找到了答案。这非常简单,并且可以正常工作:

@Html.CheckBox("RFP.DatesFlexible", Model.RFP.DatesFlexible ?? false)
@Html.Label("RFP.DatesFlexible", "My Dates are Flexible")

就像@afinkelstein接受的答案一样,只是我们不需要特殊的“编辑器模板”


1
相对于已接受的答案,此方法的另一个优点是,您可以根据应用程序的逻辑情况,决定是否将空值等同于true或false,而不是在整个应用程序中使用一个默认值(或设置两个编辑器)模板!)。
ChrisFox

25

我有bool? IsDisabled { get; set; }模特。如果在View中插入。

<div class="inputClass" id="disabled">
    <div>
    @if(Model.IsDisabled==null)
    {
        Model.IsDisabled = false;
    }           
    @Html.CheckBoxFor(model => model.IsDisabled.Value)         
    </div>
</div> 

1
效果不是很好,因为您更改了模型中的值,并且在许多情况下,false不等于null。我给了你一点,因为这是一个很好的尝试。请注意,我也同意达林():)
塞缪尔(Samuel)

7
建议您不要提出意见,因为这是一个不错的尝试,因为它可能会错误地向其他读者表明答案出现问题时很有用
克里斯(Chris)

更好看的替代方法是在呈现页面之前在控制器中将Boolean设置为false(如果为null),但仍使用.Value想法。
Graham Laight

15

我的模型有一个布尔值,必须为空

为什么?这没有道理。复选框具有两种状态:选中/未选中,或者如果愿意,则为True / False。没有第三种状态。

还是等待您在视图中使用域模型而不是视图模型?那是你的问题。因此,对我来说,解决方案是使用视图模型,在其中定义一个简单的布尔属性:

public class MyViewModel
{
    public bool Foo { get; set; }
}

现在您将使控制器动作将此视图模型传递给视图并生成适当的复选框。


26
导致foo输入根本不会出现在页面上的原因有很多。如果确实出现,那么我可以假设有一个值,但是我需要能够区分模型是在未选中foo的情况下发布还是未显示foo。
Dmulligan 2011年

@KMulligan,如何在视图模型中包含另一个布尔属性,以指示是否应为Foo属性呈现复选框,并且可以将其存储在隐藏字段中,以便在回发时知道是否应考虑Foo值或不。
达林·迪米特洛夫 Darin Dimitrov)

我最初是这样做的,但是由于种种原因,我得到了大量的原始值类型,它们可能会也可能不会包含在表单中。为所有人添加布尔值开始感到愚蠢。当我搜索nullables时,我想到了那条路。
DMulligan 2011年

4
@KMulligan,您可以编写帮助程序,编辑器模板...,以便您不必对具有此类属性的每个属性重复此操作。
达林·迪米特洛夫

25
@DarinDimitrov,您明显错过或忽略了OP表示他必须能够代表布尔值的“空”方面的事实。您对他想使用CheckBoxFor感到困惑。不要告诉他他写了“错误代码”,因为他使用了他的域模型(他可能已经做过或可能没有做过),并告诉他复选框处于选中状态还是未选中状态,而是应该尝试回答他的问题或不回答。
Andrew Steitz

7

将具有隐藏字段的原语复杂化以阐明是否建议使用False或Null。

Checkbox不是您应该使用的-实际上它只有一种状态:Checked。否则,可能是任何事情。

当您的数据库字段是可为空的布尔值时(bool?)时,UX应使用3-Radio Buttons,其中第一个按钮代表您的“已检查”,第二个按钮代表“未检查”,第三个按钮代表您的null,无论null表示。您可以使用一个<select><option>下拉列表来保存房地产,但是用户必须单击两次,选择的瞬间性就不那么明显了。

  1     0      null 
True  False  Not Set
Yes   No     Undecided
Male  Female Unknown
On    Off    Not Detected

RadioButtonList(定义为名为RadioButtonForSelectList的扩展名)为您构建单选按钮(包括选定/选中的值)并进行设置,<div class="RBxxxx">以便您可以使用CSS使单选按钮变为水平(显示:行内块),垂直或以表格形式显示(显示:行内块;宽度:100px;)

在模型中(我将string,string用于字典定义作为教学示例。您可以使用bool?,string)

public IEnumerable<SelectListItem> Sexsli { get; set; }
       SexDict = new Dictionary<string, string>()
        {
                { "M", "Male"},
                { "F", "Female" },
                { "U", "Undecided" },

        };

        //Convert the Dictionary Type into a SelectListItem Type
        Sexsli = SexDict.Select(k =>
              new SelectListItem
              {
                  Selected = (k.Key == "U"),
                  Text = k.Value,
                  Value = k.Key.ToString()
              });

<fieldset id="Gender">
<legend id="GenderLegend" title="Gender - Sex">I am a</legend>
    @Html.RadioButtonForSelectList(m => m.Sexsli, Model.Sexsli, "Sex") 
        @Html.ValidationMessageFor(m => m.Sexsli)
</fieldset>

public static class HtmlExtensions
{
public static MvcHtmlString RadioButtonForSelectList<TModel, TProperty>(
    this HtmlHelper<TModel> htmlHelper,
    Expression<Func<TModel, TProperty>> expression,
    IEnumerable<SelectListItem> listOfValues,
    String rbClassName = "Horizontal")
{
var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
var sb = new StringBuilder();

if (listOfValues != null)
{
    // Create a radio button for each item in the list 
    foreach (SelectListItem item in listOfValues)
    {
        // Generate an id to be given to the radio button field 
        var id = string.Format("{0}_{1}", metaData.PropertyName, item.Value);

        // Create and populate a radio button using the existing html helpers 
        var label = htmlHelper.Label(id, HttpUtility.HtmlEncode(item.Text));

        var radio = String.Empty;

        if (item.Selected == true)
        {
            radio = htmlHelper.RadioButtonFor(expression, item.Value, new { id = id, @checked = "checked" }).ToHtmlString();
        }
        else
        {
            radio = htmlHelper.RadioButtonFor(expression, item.Value, new { id = id }).ToHtmlString();

        }// Create the html string to return to client browser
        // e.g. <input data-val="true" data-val-required="You must select an option" id="RB_1" name="RB" type="radio" value="1" /><label for="RB_1">Choice 1</label> 

        sb.AppendFormat("<div class=\"RB{2}\">{0}{1}</div>", radio, label, rbClassName);
    }
}

return MvcHtmlString.Create(sb.ToString());
}
}

4

对我来说,解决方案是更改视图模型。考虑您正在搜索发票。这些发票可以支付或不支付。因此,您的搜索有三个选项:“付费”,“未付费”或“我不在乎”。

我最初把它设置为布尔值吗?领域:

public bool? PaidInvoices { get; set; }

这使我偶然发现了这个问题。我最终创建了一个Enum类型,并按如下方式进行处理:

@Html.RadioButtonFor(m => m.PaidInvoices, PaidStatus.NotSpecified, new { @checked = true })
@Html.RadioButtonFor(m => m.PaidInvoices, PaidStatus.Yes) 
@Html.RadioButtonFor(m => m.PaidInvoices, PaidStatus.No)

当然,我将它们包裹在标签中并指定了文本,我只是说这是要考虑的另一种选择。


这是一个有用的表示。如果空间有限,除了需要两次单击才能选择一个选项外,还可以通过下拉/选择来实现。与选择一样,浏览器之间的单选按钮看起来可能非常不同,这可能是设计者所为。
野人

4

复选框仅为您提供2个值(真,假)。Nullable布尔值具有3个值(true,false,null),因此无法使用复选框来实现。

一个不错的选择是改用下拉菜单。

模型

public bool? myValue;
public List<SelectListItem> valueList;

控制者

model.valueList = new List<SelectListItem>();
model.valueList.Add(new SelectListItem() { Text = "", Value = "" });
model.valueList.Add(new SelectListItem() { Text = "Yes", Value = "true" });
model.valueList.Add(new SelectListItem() { Text = "No", Value = "false" });

视图

@Html.DropDownListFor(m => m.myValue, valueList)

1
如果您不关心用户是否可以设置所有3个可能的值,则不能仅使用复选框就不能代表所有3个。
戴夫

@戴夫我想你完全错了。OP有笨蛋吗?表示他需要选择3种可能的值之一。如果他只想说对还是错,应该使用布尔值而不是布尔值?
Gudradain 2014年

1
实际上,OP的注释与之相反-如果表单中有一个复选框,则他根本不希望null为选项,因为当存在另一个没有复选框的表单时,该选项将被覆盖。
戴夫

我在搜索页面中使用了相同的策略。您可以搜索“是”,“否”,或在搜索中忽略布尔值。这里一个用例!:D
Jess

4

我实际上会为其创建一个模板,并将其与EditorFor()一起使用。

这是我的做法:

  1. 创建我的模板,基本上是我在EditorTemplates目录中的Shared下创建的局部视图,在Views下将其命名为(例如)CheckboxTemplate::

    @using System.Globalization    
    @using System.Web.Mvc.Html    
    @model bool?
    
    @{
        bool? myModel = false;
        if (Model.HasValue)
        {
            myModel = Model.Value;
        }
    }
    
    <input type="checkbox" checked="@(myModel)" name="@ViewData.TemplateInfo.HtmlFieldPrefix" value="True" style="width:20px;" />
  2. 这样使用它(在任何视图中):

    @ Html.EditorFor(x => x.MyNullableBooleanCheckboxToBe,“ CheckboxTemplate”)

就这样。

模板在MVC中是如此强大,请使用它们。您可以将整个页面创建为模板,并与@Html.EditorFor(); 一起使用。只要您在lambda表达式中传递其视图模型。


3

我能想到的最简洁的方法是扩展可用的扩展,HtmlHelper同时仍然重用框架提供的功能。

public static MvcHtmlString CheckBoxFor<T>(this HtmlHelper<T> htmlHelper, Expression<Func<T, bool?>> expression, IDictionary<string, object> htmlAttributes) {

    ModelMetadata modelMeta = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
    bool? value = (modelMeta.Model as bool?);

    string name = ExpressionHelper.GetExpressionText(expression);

    return htmlHelper.CheckBox(name, value ?? false, htmlAttributes);
}

我尝试对表达式进行“整形”以允许直接传递给本地人,CheckBoxFor<Expression<Func<T, bool>>>但我认为这是不可能的。


我必须更改方法的签名才能public static MvcHtmlString CheckBoxFor<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, bool?>> expression, object htmlAttributes)使它起作用:我使用了它,效果非常好。
Pierre-Loup Pagniez '17

1

我过去也遇到过类似的问题。

在HTML中创建一个Checkbox输入,并设置属性名称=“ Foo”。这仍应正确发布。

<input type="checkbox" name="Foo" checked="@model.Foo.Value" /> Foo Checkbox<br />

这似乎没有发布,我仍然为null。
Dmulligan 2011年

2
这可能与模型绑定有关
yoel halb 2014年

0

只需检查null值并返回false即可:

@{ bool nullableValue = ((Model.nullableValue == null) || (Model.nullableValue == false)) ? false : true; }
@Html.CheckBoxFor(model => nullableValue)

您知道您的财产元数据将会丢失,对吗?客户端验证,字段名称和ID等
T-moty

0

我也面临同样的问题。我尝试了以下方法来解决此问题,因为我不想更改数据库并再次生成EDMX。

@{

   bool testVar = (Model.MYVar ? true : false);

 }

<label>@Html.CheckBoxFor(m => testVar)testVar</label><br />

0

为包含可为空布尔的模型制作EditorTemplate时...

  • 将可为空的布尔拆分为2个布尔值:

    // Foo is still a nullable boolean.
    public bool? Foo 
    {
        get 
        { 
            if (FooIsNull)
                return null;
    
            return FooCheckbox;  
        }
        set
        {
            FooIsNull   = (value == null);
            FooCheckbox = (value ?? false);
        }
    }
    
    // These contain the value of Foo. Public only so they are visible in Razor views.
    public bool FooIsNull { get; set; }
    public bool FooCheckbox { get; set; }
  • 在编辑器模板中:

    @Html.HiddenFor(m => m.FooIsNull)
    
    @if (Model.FooIsNull)
    {
        // Null means "checkbox is hidden"
        @Html.HiddenFor(m => m.FooCheckbox)
    }
    else
    {
        @Html.CheckBoxFor(m => m.FooCheckbox)
    }
  • 不要回传原始属性Foo,因为现在是从FooIsNull和FooCheckbox计算得出的。


0

上面的所有答案都带有它自己的问题。IMO创建助手的最简单/最简洁的方法

MVC5剃刀

App_Code / Helpers.cshtml

@helper CheckBoxFor(WebViewPage page, string propertyName, bool? value, string htmlAttributes = null)
{
    if (value == null)
    {
        <div class="checkbox-nullable">
            <input type="checkbox" @page.Html.Raw(htmlAttributes)>
        </div>
    }
    else if (value == true)
    {
        <input type="checkbox" value="true" @page.Html.Raw(htmlAttributes) checked>
    }
    else
    {
        <input type="checkbox" value="false" @page.Html.Raw(htmlAttributes)>
    }
}

用法

@Helpers.CheckBoxFor(this, "IsPaymentRecordOk", Model.IsPaymentRecordOk)

在我的方案中,可为空的复选框表示工作人员尚未向客户询问此问题,因此将其包装为,.checkbox-nullable以便您可以适当地设置样式并帮助最终用户识别它既不是true也不是false

的CSS

.checkbox-nullable {
    border: 1px solid red;
    padding: 3px;
    display: inline-block;
}

0

扩展方法:

        public static MvcHtmlString CheckBoxFor<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, bool?>> expression)
        {
            return htmlHelper.CheckBoxFor<TModel>(expression, null);
        }
        public static MvcHtmlString CheckBoxFor<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, bool?>> expression, object htmlAttributes)
        {
            ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
            bool? isChecked = null;
            if (metadata.Model != null)
            {
                bool modelChecked;
                if (Boolean.TryParse(metadata.Model.ToString(), out modelChecked))
                {
                    isChecked = modelChecked;
                }
            }
            return htmlHelper.CheckBox(ExpressionHelper.GetExpressionText(expression), isChecked??false ,  htmlAttributes);
        }

0

单选按钮很有用,但不允许您取消选择。如果您想要这种行为,请考虑使用下拉菜单/选择。以下代码将生成,SelectList并成功绑定到可为空的布尔值:

public static SelectList GetBoolTriState()
{
    var items = new List<SelectListItem>
    {
        new SelectListItem {Value = "", Text = ""},
        new SelectListItem {Value = "True", Text = "Yes"},
        new SelectListItem {Value = "False", Text = "No"},
    };

    return new SelectList(items, "Value", "Text");
}

-1
@{  bool testVar = ((bool)item.testVar ? true : false); }
  @Html.DisplayFor(modelItem => testVar)

1
如果testVar为null,则将引发异常。
danwyand 2015年


-4

这是一个古老的问题,现有的答案描述了大多数替代方案。但是,如果您有布尔值,有一个简单的选择?在您的视图模型中,并且您不关心UI中的null:

@Html.CheckBoxFor(m => m.boolValue ?? false);

2
你有尝试过吗?由于xxxFor方法需要一个成员表达式,所以我敢打赌,这将导致运行时失败。它正在尝试确定目标属性或字段,目前不评估任何内容。
JRoughan 2014年

2
运行时错误“模板只能与字段访问,属性访问,一维数组索引或单参数自定义索引器表达式一起使用。”
ePezhman 2014年
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.