Boş değer atanabilir boole için onay kutusu


100

Modelimde boş değer atanabilir olması gereken bir boole var

public bool? Foo
{
   get;
   set;
}

Yani Razor cshtml'mde var

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

bunun dışında çalışmıyor. (Bool) ile döküm de yapmaz. Eğer yaparsam

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

bu bir hata oluşturmaz, ancak yayınlandığında modelime bağlanmaz ve foo null olarak ayarlanır. Sayfada Foo'yu görüntülemenin ve onu bir gönderideki modelime bağlamanın en iyi yolu nedir?



2
Bu iş parçacığı, null değerini 3. değer olarak algılayabilmem gereken sorunu yok sayıyor. Onay kutusu işaretlenmemiş bir form gönderimi ve onay kutusunun görüntülenmediği bir form gönderimi, dikkate alınması gereken iki farklı senaryodur.
DMulligan

Yanıtlar:


109

Onunla çalışmak için aldım

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

ve ardından Views / Shared / EditorTemplates / Boolean.cshtml'de aşağıdakilerle bir dosya oluşturun:

@model bool?

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

1
Boş değer atanabilir boole türleriyle çalışırken, bu '' '@ Html.CheckBoxFor (m => m.Foo.HasValue)' ''
Gaurav Aroraa

9
@GauravKumarArora Null yapılabilir HasValueözellik için bir onay kutusu oluşturuyorsunuz , ancak gerçek boole değeri değil. Bu, temel değerin ne olduğuna bakılmaksızın işaretli bir onay kutusu oluşturacaktır. Boş değer atanabilir bir değer varsa, her zaman doğru olacaktır.
Siewers

1
Bu kesinlikle bu sayfanın çok temiz ve esnek çözümüdür. +1
T-moty

Bu, her ikisi de aynı ada sahip iki girdi (elbette bir onay kutusu ve bir gizli form öğesi) oluşturur, gizli olanı DOM ağacında sıralanarak onay kutusunun gerçek değeri olarak sıralanır, bu nedenle siz gizli öğenin değerini işaretli / işaretsiz olarak değiştirmek için javascript kullanmak zorunda
kalacak

46

Benzer soruda cevap bulundu - Nullable Bool'u CheckBox olarak oluşturma . Çok basit ve işe yarıyor:

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

@Afinkelstein'dan kabul edilen cevap gibi, ancak özel 'düzenleyici şablonuna' ihtiyacımız yok


1
Bunun kabul edilen yanıta göre diğer bir avantajı, uygulama boyunca tek bir varsayılana sahip olmak (veya iki düzenleyici yapmak yerine, uygulamanızın mantığının belirttiği gibi, vaka bazında null değerinin doğru mu yanlış mı olduğuna karar verebilmenizdir). şablonlar!).
ChrisFox

25

Ben bool? IsDisabled { get; set; }Modeli. Görünümdeyse eklenir.

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

1
Pek iyi değil çünkü modeldeki değeri değiştiriyorsunuz ve çoğu durumda false null'a eşit değildir. Sana bir puan verdim çünkü güzel bir deneme. Darin ile de aynı fikirdeyim :)
Samuel

7
Bir noktaya değinmemeyi önerin çünkü bu güzel bir denemedir , çünkü diğer okuyuculara problemler olduğunda cevabın yararlı olduğunu yanlış bir şekilde gösterebilir .
Chris

Daha iyi görünen bir alternatif, sayfayı oluşturmadan önce null ise denetleyicide Boolean değerini false olarak ayarlamak, ancak yine de .Value fikrini kullanmaktır.
Graham Laight

15

Modelimde boş değer atanabilir olması gereken bir boole var

Neden? Bu mantıklı değil. Bir onay kutusunun iki durumu vardır: işaretli / işaretli değil veya isterseniz Doğru / Yanlış. Üçüncü durum yok.

Yoksa görünüm modelleri yerine görünümlerinizde etki alanı modellerinizi mi kullanıyorsunuz? Bu senin problemin. Dolayısıyla benim için çözüm, basit bir boole özelliği tanımlayacağınız bir görünüm modeli kullanmaktır:

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

ve şimdi denetleyici eyleminizin bu görünüm modelini görünüme geçirmesini ve uygun onay kutusunu oluşturmasını sağlayacaksınız.


26
Foo girişinin sayfada görünmemesinin sayısız farklı nedeni vardır. Görünüyorsa, bir değer olduğunu varsayabilirim, ancak modelin işaretlenmemiş olarak foo ile gönderildiği ve foo'nun gösterilmediği zaman arasında ayrım yapabilmem gerekiyor.
DMulligan

@KMulligan, görünüm modelinize Foo mülkü için bir onay kutusu oluşturup oluşturmayacağınızı ve gizli bir alanda saklanıp saklanmayacağını belirten başka bir boole özelliği eklemeye ne dersiniz? Böylece geri gönderirken Foo değerini hesaba katmanız gerekip gerekmediğini bilirsiniz ya da değil.
Darin Dimitrov

Bunu başlangıçta yaptım, ancak çeşitli nedenlerle formlarıma dahil edilebilecek veya edilmeyebilecek bu ilkel değer türlerinden tonlarca var. Hepsi için boole eklemek aptalca hissetmeye başladı. Nullable'ları Google'da aradığımda, bunun gitmenin yolu olduğunu anladım.
DMulligan

4
@KMulligan, yardımcılar, düzenleyici şablonları yazabilirsiniz ... böylece bu tür özelliklere sahip her özellik için bunu tekrarlamak zorunda kalmazsınız.
Darin Dimitrov

25
@DarinDimitrov, OP'nin bool'un "boş" yönünü temsil etmesi gerektiğini söylediği gerçeğini açıkça gözden kaçırdın veya görmezden geldin. CheckBoxFor'u kullanmak istediği gerçeğine takıldınız. Ona etki alanı modelini kullandığı için "kötü kod" yazdığını (yapmış olabilir ya da yapmamış olabilir) ve onay kutularının işaretli ya da işaretli olmadığını söylemek yerine, sorusunu yanıtlamaya çalışmalı ya da yanıtlamamalısınız.
Andrew Steitz

7

False veya Null'un önerilmediğini açıklığa kavuşturmak için bir ilkeli gizli alanlarla karıştırmak

Onay kutusu, kullanmanız gereken şey değildir - gerçekten yalnızca bir duruma sahiptir: İşaretli . Aksi takdirde, herhangi bir şey olabilir.

Veritabanı alanınız boş değer atanabilir bir boolean ( bool?) olduğunda, kullanıcı deneyimi 3-Radyo Düğmelerini kullanmalıdır; burada ilk düğme "Kontrol Edildi" i, ikinci düğme "Kontrol Edilmedi" i temsil eder ve üçüncü düğme boş değerinizi temsil eder. boş anlamına gelir. <select><option>Gayrimenkul kaydetmek için bir açılır liste kullanabilirsiniz, ancak kullanıcının iki kez tıklaması gerekir ve seçimler neredeyse anında net değildir.

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

RadioButtonForSelectList adlı bir uzantı olarak tanımlanan RadioButtonList, sizin için seçilen / işaretlenen değer dahil radyo düğmelerini oluşturur ve radyo düğmelerinizin <div class="RBxxxx">yatay (ekran: satır içi blok), dikey veya tablo tarzında (ekran: inline-block; genişlik: 100px;)

Modelde (pedagojik bir örnek olarak sözlük tanımı için string, string kullanıyorum. Bool ?, string kullanabilirsiniz)

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

Benim için çözüm, görünüm modelini değiştirmekti. Fatura aradığınızı düşünün. Bu faturalar ödenebilir veya ödenemez. Dolayısıyla aramanızın üç seçeneği vardır: Ücretli, Ödenmemiş veya "Önemsemiyorum".

Bunu başlangıçta bir bool olarak mı ayarlamıştım? alan:

public bool? PaidInvoices { get; set; }

Bu beni bu soruya tökezledi. Sonunda bir Enum türü oluşturdum ve bunu şu şekilde ele aldım:

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

Tabii ki onları etiketlere sarmıştım ve metni belirtmiştim, sadece burada dikkate alınması gereken başka bir seçenek var.


Bu yararlı bir temsildir. Sınırlı alanınız varsa, bir seçeneği seçmek için iki tıklama gerekmesi dışında, bunu açılır menü / seç ile de gerçekleştirebilirsiniz. Seçmelerde olduğu gibi, radyo düğmeleri tarayıcılar arasında çok farklı görünebilir ve bu tasarımcı cehennemi olabilir.
Savage

4

Onay kutusu size yalnızca 2 değer sunar (doğru, yanlış). Nullable boolean 3 değere sahiptir (true, false, null), bu yüzden bunu bir onay kutusuyla yapmak imkansızdır.

Bunun yerine bir açılır menü kullanmak iyi bir seçenektir.

Modeli

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

Kontrolör

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

Görünüm

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

1
Kullanıcının 3 olası değeri de ayarlayabilmesini umursamıyorsanız, yalnızca bir onay kutusu kullanarak 3 değerini de gösterememeniz önemli değildir.
Dave

@ Dave Bence asıl noktayı tamamen kaçırdın. OP'nin yankılanması mı var? 3 olası değerden birini seçmesi gerektiği anlamına gelir. Yalnızca doğru veya yanlış olmasını istiyorsa, bool değil, bool kullanmalı mı?
Gudradain

1
Aslında, OP'nin yorumu bunun tam tersini gösterir - formda bir onay kutusu varsa, boş seçeneğin bir seçenek olmasını istemez, çünkü bu seçenek, onay kutusu olmayan farklı bir form olduğunda kapsanır.
Dave

Aynı stratejiyi bir arama sayfasında kullandım. Evet, Hayır olarak arayabilir veya aramanızda boole değerini göz ardı edebilirsiniz. Orada olan bir kullanım örneği! : D
Jess

4

Aslında bunun için bir şablon oluşturur ve bu şablonu EditorFor () ile kullanırdım.

İşte böyle yaptım:

  1. Temelde EditorTemplates dizininde oluşturduğum kısmi bir görünüm olan Şablonumu Oluştur, Paylaşılanlar altında Görünümler altında şöyle adlandırın (örneğin) 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. Bunu şu şekilde kullanın (herhangi bir görünümde):

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

Bu kadar.

MVC'de şablonlar çok güçlüdür, onları kullanın .. Tüm bir sayfayı şablon olarak oluşturabilirsiniz, bununla birlikte kullanacağınız @Html.EditorFor(); görünüm modelini lambda ifadesinde geçirmeniz şartıyla ..


3

Bulabildiğim en temiz yaklaşım HtmlHelper, çerçeve tarafından sağlanan işlevselliği yeniden kullanırken mevcut uzantıları genişletmektir .

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

İfadeyi yerliden doğrudan geçişe izin verecek şekilde 'şekillendirmeyi' denedim CheckBoxFor<Expression<Func<T, bool>>>ama bunun mümkün olduğunu sanmıyorum.


Bunun benim için çalışması için yöntemin imzasını değiştirmek zorunda kaldım: kullandım public static MvcHtmlString CheckBoxFor<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, bool?>> expression, object htmlAttributes)ve harika çalıştı.
Pierre-Loup Pagniez

1

Geçmişte de benzer bir sorun yaşadım.

HTML'de bir Onay Kutusu girişi oluşturun ve name = "Foo" niteliğini ayarlayın Bu yine de düzgün şekilde gönderilmelidir.

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

Bu yayınlanıyor gibi görünmüyor, hala boş kalıyorum.
DMulligan

2
Bunun model bağlamayla ilgili sorunları olabilir
yoel halb

0

Sadece boş değeri kontrol edin ve buna yanlış döndürün:

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

Mülk meta verilerinizin kaybolacağını biliyorsunuz, değil mi? İstemci tarafı doğrulama, alan adı ve kimliği, vb.
T-moty

0

Ben de aynı sorunla karşılaştım. Sorunu çözmek için aşağıdaki yaklaşımı denedim çünkü DB'yi değiştirmek ve tekrar EDMX'i oluşturmak istemiyorum.

@{

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

 }

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

0

Boş değer atanabilir bool içeren bir model için EditorTemplate oluştururken ...

  • Boş değer atanabilir bool'u 2 boole'ye bölün:

    // 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; }
    
  • Editör şablonunun içinde:

    @Html.HiddenFor(m => m.FooIsNull)
    
    @if (Model.FooIsNull)
    {
        // Null means "checkbox is hidden"
        @Html.HiddenFor(m => m.FooCheckbox)
    }
    else
    {
        @Html.CheckBoxFor(m => m.FooCheckbox)
    }
    
  • Orijinal Foo özelliğini geri göndermeyin, çünkü bu artık FooIsNull ve FooCheckbox'tan hesaplanıyor.


0

Yukarıdaki tüm cevaplar kendi sorunları ile geldi. IMO'nun en kolay / en temiz yolu bir yardımcı yaratmaktır

MVC5 Jilet

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

Kullanım

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

Bir sarılı yani benim senaryoda, bir null onay kutusu vasıtası henüz müşteriye soru soruldu değil bir personel olduğunu .checkbox-nullablesen ne uygun stil ve son kullanıcı o olduğunu tespit edilmesine yardımcı olabilir böylece truene defalse

CSS

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

0

Uzatma yöntemleri:

        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

Radyo düğmeleri kullanışlıdır, ancak seçimi kaldırmanıza izin vermezler . Bu davranışı istiyorsanız, bir açılır menü / seçim kullanmayı düşünün. Aşağıdaki kod, SelectListve bu null yapılabilir bir boole'ye başarıyla bağlanır:

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 boş ise bu bir istisna atar.
danwyand


-4

Bu eski bir sorudur ve mevcut cevaplar alternatiflerin çoğunu açıklamaktadır. Bool varsa ama basit bir seçenek var mı? görünüm modelinizde ve kullanıcı arayüzünüzdeki boş değeri umursamıyorsunuz:

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

2
Bunu denedin mi XxxFor yöntemleri bir üye ifadesi beklediğinden, bunun bir çalışma zamanı hatası oluşturacağına dair iyi para yatırırdım. Bu noktada hiçbir şeyi değerlendirmeden, hedef özelliği veya alanı belirlemeye çalışıyor.
JRoughan

2
çalışma zamanı hatası "Şablonlar yalnızca alan erişimi, özellik erişimi, tek boyutlu dizi dizini veya tek parametreli özel dizin oluşturucu ifadeleriyle kullanılabilir."
ePezhman
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.