复选框是否可以为空的布尔值

时间:2011-07-27 19:02:24

标签: asp.net-mvc-3 razor nullable

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

public bool? Foo
{
   get;
   set;
}

所以在我的Razor cshtml中我有

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

除了不起作用。也没有(bool)施放它。如果我做

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

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

20 个答案:

答案 0 :(得分:99)

我让它与

一起工作
@Html.EditorFor(model => model.Foo) 

然后在我的EditorTemplates文件夹中创建一个Boolean.cshtml并坚持

@model bool?

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

答案 1 :(得分:37)

在类似问题中找到答案 - Rendering Nullable Bool as CheckBox。 这非常简单,只是有效:

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

这就像@afinkelstein接受的回答,除了我们不需要特殊的'编辑模板'

答案 2 :(得分:24)

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

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

答案 3 :(得分:14)

  

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

为什么呢?这没有意义。复选框有两种状态:已选中/未选中,如果有,则为真/假。没有第三国。

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

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

现在您将让控制器操作将此视图模型传递给视图并生成正确的复选框。

答案 4 :(得分:6)

使用隐藏字段复杂原语,以澄清是否不建议使用False或Null。

复选框不是您应该使用的 - 它实际上只有一个状态:已选中。否则,它可能是任何东西。

当您的数据库字段是可以为空的布尔值(bool?)时,UX应使用3-Radio按钮,其中第一个按钮代表“已检查”,第二个按钮代表“未选中”,第三个按钮代表“未选中”表示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;)

在模型中(我使用字符串,字符串定义的字符串作为教学示例。你可以使用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());
}
}

答案 5 :(得分:3)

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

我最初设置为bool?字段:

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)

当然我把它们包裹在标签中并指定了文字,我只是说这是另一种选择。

答案 6 :(得分:3)

复选框仅提供2个值(true,false)。 Nullable boolean有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)

答案 7 :(得分:3)

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

我是这样做的:

  1. 创建我的模板,它基本上是我在EditorTemplates目录中创建的部分视图,位于“共享”下,在“视图”下将其命名为(例如):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 =&gt; x.MyNullableBooleanCheckboxToBe,&#34; CheckboxTemplate&#34;)

  3. 多数人。

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

答案 8 :(得分: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>>>但我不认为这是可能的。

答案 9 :(得分:1)

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

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

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

答案 10 :(得分:0)

只需检查空值并向其返回false:

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

答案 11 :(得分:0)

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

@{

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

 }

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

答案 12 :(得分:0)

为包含可以为空的bool的模型制作EditorTemplate时...

  • 将可空的bool分成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计算。

答案 13 :(得分:0)

上面的所有答案都伴随着它自己的问题。 IMO创建帮助者的最简单/最干净的方法

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

<强>用法

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

在我的场景中,可以为空的复选框意味着工作人员尚未向客户提出问题,因此它包含在.checkbox-nullable中,以便您可以适当地设计样式并帮助最终用户识别它既不是true也不是false

<强> CSS

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

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

答案 15 :(得分:0)

您可以尝试这样

grep 'vagrant@node' ~/.ssh/authorized_keys &>/dev/null || {
  cat /vagrant/id_rsa.pub >> ~/.ssh/authorized_keys
  chmod 0600 ~/.ssh/authorized_keys
}

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

答案 17 :(得分:0)

如果选中 = True 而未选中 = null

型号

public NotNullFoo
{
    get { return this.Foo?? false; }
    set { this.Foo= (value == false ? null : true as bool?); }
}


public bool? Foo
{
   get;
   set;
}

查看

  @Html.CheckBoxFor(x => Model.NotNullFoo })

答案 18 :(得分:-1)

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

答案 19 :(得分:-3)

这是一个老问题,现有答案描述了大多数替代方案。但是有一个简单的选择,如果你有bool?在您的viewmodel中,您不关心UI中的null:

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