Casella di controllo per nullable booleano

Il mio modello ha un valore booleano che deve essere annullabile

public bool? Foo { get; set; } 

così nel mio Razor cshtml che ho

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

tranne che non funziona. Neanche lo lancia con (bool). Se lo faccio

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

questo non crea un errore, ma non si lega al mio modello quando postato e foo è impostato su null. Qual è il modo migliore per mostrare Foo sulla pagina e renderlo legato al mio modello su un post?

Ho avuto modo di lavorare con

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

e quindi creare un Boolean.cshtml nella mia cartella EditorTemplates e incollarlo

 @model bool? @Html.CheckBox("", Model.GetValueOrDefault()) 

dentro.

Risposta trovata in una domanda simile – Rendering Nullable Bool come CheckBox . È molto semplice e funziona semplicemente:

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

È come una risposta accettata da @afinkelstein, tranne che non abbiamo bisogno di un “modello editor” speciale

Ho bool? IsDisabled { get; set; } bool? IsDisabled { get; set; } bool? IsDisabled { get; set; } in Model. Inserito se in Visualizza.

 
@if(Model.IsDisabled==null) { Model.IsDisabled = false; } @Html.CheckBoxFor(model => model.IsDisabled.Value)

Il mio modello ha un valore booleano che deve essere annullabile

Perché? Questo non ha senso. Una casella di controllo ha due stati: selezionato / deselezionato, o Vero / Falso, se lo si desidera. Non c’è nessun terzo stato.

O aspetti di utilizzare i tuoi modelli di dominio nelle visualizzazioni anziché i modelli di visualizzazione? Questo è il tuo problema. Quindi la soluzione per me è usare un modello di vista in cui definirai una semplice proprietà booleana:

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

e ora l’azione del controller passerà questo modello di visualizzazione alla vista e genererà la casella di controllo appropriata.

Complicare una primitiva con campi nascosti per chiarire se False o Null non è raccomandato.

La casella di controllo non è ciò che dovresti usare: in realtà ha solo uno stato: selezionato. Altrimenti, potrebbe essere qualsiasi cosa.

Quando il tuo campo di database è un valore nullo booleano ( bool? ), L’UX dovrebbe usare 3 pulsanti Radio, dove il primo pulsante rappresenta il tuo “Controllato”, il secondo pulsante rappresenta “Non verificato” e il terzo pulsante rappresenta il tuo null, qualunque sia il semantica di mezzi nulli. È ansible utilizzare un tendina per salvare gli immobili, ma l’utente deve fare clic due volte e le scelte non sono altrettanto istantanee.

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

Il RadioButtonList, definito come un’estensione denominata RadioButtonForSelectList, crea i pulsanti di opzione per te, compreso il valore selezionato / controllato, e imposta

così puoi usare css per far andare i pulsanti radio orizzontali (display: inline-block), verticale o in modo tabella (display: inline-block; width: 100px;)

Nel modello (sto usando stringa, stringa per la definizione del dizionario come esempio pedagogico. Puoi usare bool ?, stringa)

 public IEnumerable Sexsli { get; set; } SexDict = new Dictionary() { { "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() }); 
I am a @Html.RadioButtonForSelectList(m => m.Sexsli, Model.Sexsli, "Sex") @Html.ValidationMessageFor(m => m.Sexsli)
public static class HtmlExtensions { public static MvcHtmlString RadioButtonForSelectList( this HtmlHelper htmlHelper, Expression> expression, IEnumerable 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 // eg sb.AppendFormat("
{0}{1}
", radio, label, rbClassName); } } return MvcHtmlString.Create(sb.ToString()); } }

Per me la soluzione era cambiare il modello di visualizzazione. Considera che stai cercando fatture. Queste fatture possono essere pagate o meno. Quindi la tua ricerca ha tre opzioni: a pagamento, non retribuito o “Non mi interessa”.

L’avevo originariamente impostato come bool? campo:

 public bool? PaidInvoices { get; set; } 

Questo mi ha fatto inciampare su questa domanda. Ho finito per creare un tipo Enum e ho gestito questo come segue:

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

Certo che li ho avvolti in etichette e ho specificato il testo, voglio solo dire che qui c’è un’altra opzione da considerare.

La casella di controllo offre solo 2 valori (vero, falso). Nullable boolean ha 3 valori (true, false, null) quindi è imansible farlo con una casella di controllo.

Una buona opzione è usare invece un menu a discesa.

Modello

 public bool? myValue; public List valueList; 

controllore

 model.valueList = new List(); 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" }); 

vista

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

L’approccio più pulito che potrei trovare è di espandere le estensioni disponibili per HtmlHelper mentre HtmlHelper ancora a riutilizzare la funzionalità fornita dal framework.

 public static MvcHtmlString CheckBoxFor(this HtmlHelper htmlHelper, Expression> expression, IDictionary 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); } 

Ho sperimentato con ‘shaping’ l’espressione per consentire un passaggio diretto al controllo nativo CheckBoxFor>> ma non credo sia ansible.

Ho avuto un problema simile in passato.

Crea un input Checkbox in HTML e imposta l’attributo name = “Foo” Questo dovrebbe ancora essere pubblicato correttamente.

  Foo Checkbox

In realtà creerei un modello per esso e userei quel modello con un EditorFor ().

Ecco come l’ho fatto:

  1. Crea il mio modello, che è fondamentalmente una vista parziale che ho creato nella directory EditorTemplates, sotto Condivisi, sotto Visualizza il nome come (per esempio): CheckboxTemplate :

     @using System.Globalization @using System.Web.Mvc.Html @model bool? @{ bool? myModel = false; if (Model.HasValue) { myModel = Model.Value; } }  
  2. Usalo in questo modo (in ogni vista):

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

È tutto.

I modelli sono così potenti in MVC, li usano .. Puoi creare un’intera pagina come modello, che @Html.EditorFor() con @Html.EditorFor() ; purché tu passi il suo modello di vista nell’espressione lambda ..

Basta controllare il valore nullo e restituire false ad esso:

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

Ho anche affrontato lo stesso problema. Ho provato il seguente approccio per risolvere il problema perché non voglio modificare il DB e generare nuovamente EDMX.

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

Quando si crea un EditorTemplate per un modello che contiene un bool nullable …

  • Dividere il bool nullable in 2 booleani:

     // 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; } 
  • All’interno del modello di editor:

     @Html.HiddenFor(m => m.FooIsNull) @if (Model.FooIsNull) { // Null means "checkbox is hidden" @Html.HiddenFor(m => m.FooCheckbox) } else { @Html.CheckBoxFor(m => m.FooCheckbox) } 
  • Non postback della proprietà originale Foo, perché ora è calcasting da FooIsNull e FooCheckbox.

Tutte le risposte di cui sopra sono venute con i suoi stessi problemi. Il modo più semplice / pulito IMO è creare un helper

MVC5 Razor

App_Code / Helpers.cshtml

 @helper CheckBoxFor(WebViewPage page, string propertyName, bool? value, string htmlAttributes = null) { if (value == null) { 
} else if (value == true) { } else { } }

uso

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

Nel mio scenario, una casella di controllo nullable significa che un membro dello staff non aveva ancora fatto la domanda al client, quindi è racchiusa in un .checkbox-nullable modo da poter essere .checkbox-nullable modo appropriato e aiutare l’utente a identificare che non è né truefalse

CSS

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

Metodi di estensione:

  public static MvcHtmlString CheckBoxFor(this HtmlHelper htmlHelper, Expression> expression) { return htmlHelper.CheckBoxFor(expression, null); } public static MvcHtmlString CheckBoxFor(this HtmlHelper htmlHelper, Expression> 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); } 
 @{ bool testVar = ((bool)item.testVar ? true : false); } @Html.DisplayFor(modelItem => testVar) 

Questa è una vecchia domanda e le risposte esistenti descrivono la maggior parte delle alternative. Ma c’è una semplice opzione, se hai il bool? nel tuo viewmodel, e non ti interessa nulla nella tua interfaccia utente:

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