null可能なブール値のチェックボックス


97

私のモデルにはnullにする必要があるブール値があります

public bool? Foo
{
   get;
   set;
}

私のRazor cshtmlには

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

それが機能しないことを除いて。(bool)でキャストすることもできません。私が行った場合

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

エラーは発生しませんが、投稿時にモデルにバインドされず、fooがnullに設定されます。ページにFooを表示し、投稿のモデルにバインドする最良の方法は何ですか?



2
このスレッドは、nullを3番目の値として検出できるようにする必要があるという問題を無視します。チェックボックスがオフになっているフォーム送信と、チェックボックスが表示されなかったフォーム送信は、2つの異なるシナリオを考慮する必要があります。
DMulligan 2011

回答:


107

一緒に使う

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

そして、EditorTemplatesフォルダーにBoolean.cshtmlを作成し、

@model bool?

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

内部。


2
私のために働く。ありがとう!
サミュエル

1
null許容のブール型を操作しているときに、これを使用しました '' '@ Html.CheckBoxFor(m => m.Foo.HasValue)' ''
Gaurav Aroraa

9
@GauravKumarArora nullable HasValueプロパティのチェックボックスを作成していますが、実際のブール値は作成していません。これにより、基になる値に関係なく、チェックされたチェックボックスが作成されます。nullableに値がある場合、常にtrueになります。
Siewers

1
これは間違いなく、このページの非常にクリーンで柔軟なソリューションです。+1
T-moty

2
注:1.このファイルを「Views / Shared / 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
受け入れられた回答に対するこれのもう1つの利点は、アプリケーション全体で単一のデフォルトを持つ(または2つのエディターを作成するのではなく)テンプレート!)。
ChrisFox 2018年

25

私は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> 

1
モデルの値を変更するため、あまりよくありません。多くの場合、falseはnullと等しくありません。いい試みなのでポイントをあげました。私もダーリンに同意することに注意してください:)
サミュエル

7
ポイントを与えることはお勧めしません。他の読者に、問題が発生したときに答えが役立つと誤って示す可能性があるためです。
クリス

より見栄えの良い代替策は、ページをレンダリングする前にnullの場合、コントローラーでブール値をfalseに設定することですが、それでも.Valueのアイデアを使用します。
Graham Laight

15

私のモデルにはnullにする必要があるブール値があります

どうして?これは意味がありません。チェックボックスには2つの状態があります:オン/オフ、または必要に応じてTrue / False。3番目の状態はありません。

または、ビューモデルではなくビューでドメインモデルを使用しているのを待ちますか?それはあなたの問題だ。したがって、私にとっての解決策は、単純なブールプロパティを定義するビューモデルを使用することです。

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

これで、コントローラーアクションがこのビューモデルをビューに渡し、適切なチェックボックスを生成するようになります。


26
foo入力がページにまったく表示されない理由は無数にあります。表示される場合は値があると想定できますが、モデルがfooでチェックされていない状態で投稿されたときと、fooが表示されていないときを区別できるようにする必要があります。
DMulligan 2011

@KMulligan、ビューモデルに別のブールプロパティを含めて、Fooプロパティのチェックボックスを表示する必要があるかどうかを示し、ポストバック時にFoo値を考慮する必要があるかどうかがわかるように、非表示フィールドに格納できるかどうかを示しますか否か。
Darin Dimitrov

私は元々そうしましたが、さまざまな理由でフォームに含まれている場合も含まれていない場合もあるこれらのプリミティブな値の型を大量に取得しました。それらすべてにブール値を追加すると、ばかげた感じがし始めました。nullableをグーグル検索したとき、それが方法だと思いました。
DMulligan 2011

4
@KMulligan、ヘルパー、エディターテンプレートなどを記述できるので、そのようなプロパティを持つすべてのプロパティに対してこれを繰り返す必要はありません。
Darin Dimitrov 2011

25
@DarinDimitrov、あなたは、OPがブールの「ヌル」の側面を表すことができる必要があると述べたという事実を明らかに見逃しましたか、無視しました。あなたは、彼がCheckBoxForを使用したいと思っていたという事実に電話を切りました。彼がドメインモデルを使用したために「悪いコード」を書いたと彼に告げる代わりに(彼はそうしたかもしれないしそうでなかったかもしれませんが)、チェックボックスがチェックされているかチェックされていないかのどちらかであると彼に告げる代わりに、あなたは彼の質問に答えようとしたか応答しなかったはずです。
Andrew Steitz

7

非表示フィールドを持つプリミティブを複雑にして、FalseまたはNullが推奨されないかどうかを明確にします。

チェックボックスはあなたが使用するべきものではありません-それは実際には1つの状態しかありません:チェック済みです。それ以外の場合は、何でもかまいません。

データベースフィールドがnull可能なブール値(bool?)の場合、UXは3つのラジオボタンを使用する必要があります。最初のボタンは「チェック済み」を表し、2番目のボタンは「チェックなし」を表し、3番目のボタンはnullを表します。 nullは意味します。<select><option>ドロップダウンリストを使用して不動産を節約することもできますが、ユーザーは2回クリックする必要があり、選択肢が瞬時に明確になるわけではありません。

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

RadioButtonListは、RadioButtonForSelectListという名前の拡張として定義され、ラジオボタンを作成し、選択済み/チェック済みの値を含め、<div class="RBxxxx">CSSを使用してラジオボタンを水平(表示:インラインブロック)、垂直、またはテーブル形式(display:inline-block; width:100px;)

モデルで(私は文字列を使用していますが、教育的な例として辞書の定義に文字列を使用しています。bool?、文字列を使用できます)

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

私にとっての解決策は、ビューモデルを変更することでした。請求書を探しているとしましょう。これらの請求書は支払われてもされなくてもかまいません。したがって、検索には3つのオプションがあります:有償、無給、または「私は気にしません」。

私はもともとこれをブール値として設定しましたか?フィールド:

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)

もちろん、それらをラベルで包み、テキストを指定しましたが、ここで検討すべき別のオプションがあることを意味します。


これは便利な表現です。スペースが限られている場合は、ドロップダウン/選択を使用してこれを実現することもできますが、オプションを選択するには2回のクリックが必要です。選択の場合と同様に、ラジオボタンはブラウザー間で非常に異なって見える可能性があり、それはデザイナーの地獄になる可能性があります。
サベージ

4

チェックボックスは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)

1
ユーザーが3つすべての可能な値を設定できることを気にしない場合、チェックボックスだけを使用して3つすべてを表すことができないことは問題ではありません。
デイブ

@デイブあなたは完全にポイントを逃したと思います。OPにはブールがありますか?つまり、3つの可能な値のいずれかを選択する必要があります。trueまたはfalseのみを取得したい場合、ブールではなくブールを使用する必要がありますか?
Gudradain、2014年

1
実際、OPのコメントは反対を示しています。フォームにチェックボックスがある場合、チェックボックスのない別のフォームがあるときにそのオプションがカバーされるため、彼はnullをオプションにしたくありません。
デイブは

私はこれと同じ戦略を検索ページで使用しました。「はい」、「いいえ」を検索するか、ブール値を無視して検索できます。そこユースケースは!:D
ジェス

4

実際にテンプレートを作成し、そのテンプレートをEditorFor()で使用します。

ここに私がそれをした方法があります:

  1. 私のテンプレートを作成します。これは、基本的に、EditorsTemplatesディレクトリの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()。ラムダ式でビューモデルを渡すことを条件とします。


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 2017

1

過去にも同様の問題がありました。

HTMLでチェックボックス入力を作成し、name = "Foo"属性を設定します。これでも適切に投稿されます。

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

これは投稿されていないようです。まだnullになります。
DMulligan 2011

2
モデルのバインディングに問題がある可能性があります
yoel halb '19年

0

null値を確認してfalseを返すだけです。

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

プロパティのメタデータが失われることをご存知ですか?クライアント側の検証、フィールド名とIDなど
T-moty

0

私も同じ問題に直面しました。DBを変更してEDMXを再度生成したくないので、次の方法で問題を解決しました。

@{

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

 }

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

0

null可能なブール値を含むモデルのEditorTemplateを作成するとき...

  • null許容ブール値を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)

私のシナリオでは、Nullableチェックボックスは、スタッフがクライアントにまだ質問していないことを意味する.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、これはnull許容ブール値に正常にバインドします。

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

これは古い質問であり、既存の回答はほとんどの選択肢を説明しています。しかし、もしあなたがブールを持っているなら、1つの簡単なオプションがありますか?あなたのviewmodelで、あなたはUIでnullを気にしません:

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

2
やってみましたか?xxxForメソッドはメンバー式を想定しているので、これが実行時エラーを生成することになるとは思いません。この時点では何も評価せず、対象のプロパティまたはフィールドを特定しようとしています。
JRoughan 2014

2
実行時エラー「テンプレートは、フィールドアクセス、プロパティアクセス、1次元配列インデックス、または1パラメータのカスタムインデクサー式でのみ使用できます。」
ePezhman 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.