Checkbox for nullable boolean

2019-01-04 00:51发布

My model has a boolean that has to be nullable

public bool? Foo
{
   get;
   set;
}

so in my Razor cshtml I have

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

except that doesn't work. Neither does casting it with (bool). If I do

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

that doesn't create an error, but it doesn't bind to my model when posted and foo is set to null. Whats the best way to display Foo on the page and make it bind to my model on a post?

17条回答
Rolldiameter
2楼-- · 2019-01-04 01:24

For me the solution was to change the view model. Consider you are searching for invoices. These invoices can be paid or not. So your search has three options: Paid, Unpaid, or "I don't Care".

I had this originally set as a bool? field:

public bool? PaidInvoices { get; set; }

This made me stumble onto this question. I ended up created an Enum type and I handled this as follows:

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

Of course I had them wrapped in labels and had text specified, I just mean here's another option to consider.

查看更多
仙女界的扛把子
3楼-- · 2019-01-04 01:25

All the answers above came with it's own issues. Easiest/cleanest way IMO is to create a helper

MVC5 Razor

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)>
    }
}

Usage

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

In my scenario, a nullable checkbox means that a staff member had not yet asked the question to the client, so it's wrapped in a .checkbox-nullable so that you may style appropriately and help the end-user identify that it is neither true nor false

CSS

.checkbox-nullable {
    border: 1px solid red;
    padding: 3px;
    display: inline-block;
}
查看更多
Emotional °昔
4楼-- · 2019-01-04 01:26

My model has a boolean that has to be nullable

Why? This doesn't make sense. A checkbox has two states: checked/unchecked, or True/False if you will. There is no third state.

Or wait you are using your domain models in your views instead of view models? That's your problem. So the solution for me is to use a view model in which you will define a simple boolean property:

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

and now you will have your controller action pass this view model to the view and generate the proper checkbox.

查看更多
叛逆
5楼-- · 2019-01-04 01:26

I would actually create a template for it and use that template with an EditorFor().

Here is how I did it:

  1. Create My template, which is basically a partial view I created in the EditorTemplates directory, under Shared, under Views name it as (for example): 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. Use it like this (in any view):

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

Thats all.

Templates are so powerful in MVC, use them.. You can create an entire page as a template, which you would use with the @Html.EditorFor(); provided that you pass its view model in the lambda expression..

查看更多
欢心
6楼-- · 2019-01-04 01:29

Just check for the null value and return false to it:

@{ bool nullableValue = ((Model.nullableValue == null) || (Model.nullableValue == false)) ? false : true; }
@Html.CheckBoxFor(model => nullableValue)
查看更多
狗以群分
7楼-- · 2019-01-04 01:31

When making an EditorTemplate for a model which contains a nullable bool...

  • Split the nullable bool into 2 booleans:

    // 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; }
    
  • Within the editor template:

    @Html.HiddenFor(m => m.FooIsNull)
    
    @if (Model.FooIsNull)
    {
        // Null means "checkbox is hidden"
        @Html.HiddenFor(m => m.FooCheckbox)
    }
    else
    {
        @Html.CheckBoxFor(m => m.FooCheckbox)
    }
    
  • Do not postback the original property Foo, because that is now calculated from FooIsNull and FooCheckbox.

查看更多
登录 后发表回答