Case à cocher pour le booléen nul

mon modèle a un booléen qui doit être nul

public bool? Foo
{
   get;
   set;
}

donc dans mon rasoir cshtml j'ai

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

sauf que ça ne marche pas. Ni le moulage avec (bool). Si je fais

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

qui ne crée pas d'erreur, mais qui ne se lie pas à mon modèle lorsqu'il est affiché et foo est défini à null. Quelle est la meilleure façon d'afficher Foo sur la page et de le lier à mon modèle sur un post?

81
demandé sur Erik Philips 2011-07-27 23:02:24

17 réponses

je l'ai eu à travailler avec

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

et ensuite faire un Booléen.cshtml dans mon dossier Editoremplates et coller

@model bool?

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

à l'intérieur.

93
répondu DMulligan 2014-11-21 00:33:20

réponse trouvée dans la question similaire - rendre nul Bool comme case à cocher . Il est très simple et fonctionne tout simplement:

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

c'est comme la réponse acceptée de @afinkelstein sauf que nous n'avons pas besoin de 'modèle d'éditeur 'spécial

32
répondu resnyanskiy 2017-05-23 12:10:11

j'ai bool? IsDisabled { get; set; } dans le modèle. Insérée si en vue.

<div class="inputClass" id="disabled">
    <div>
    @if(Model.IsDisabled==null)
    {
        Model.IsDisabled = false;
    }           
    @Html.CheckBoxFor(model => model.IsDisabled.Value)         
    </div>
</div> 
25
répondu VitalyB 2015-01-05 18:41:58

mon modèle a un booléen qui doit être nul

pourquoi? Ce n'est pas logique. Une case à cocher a deux états: checked/unchecked, ou True / False si vous voulez. Il n'y a aucun état tiers.

ou attendez vous utilisez vos modèles de domaine dans vos vues au lieu de modèles de vue? C'est votre problème. Donc la solution pour moi est d'utiliser un modèle de vue dans lequel vous définirez une propriété booléenne simple:

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

et maintenant vous aurez votre action de contrôleur passer Ce modèle de vue à la vue et générer la case à cocher appropriée.

14
répondu Darin Dimitrov 2011-07-27 19:13:36

compliquer une primitive avec des champs cachés pour clarifier si faux ou Null n'est pas recommandé.

La case à cocher

n'est pas ce que vous devriez utiliser -- elle n'a qu'un seul État: coché . Sinon, il pourrait être n'importe quoi.

lorsque votre champ de base de données est un booléen nul ( bool? ), le UX doit utiliser 3 boutons Radio, où le premier bouton représente votre "coché", le second bouton représente "non coché"" et le troisième bouton représente votre null, quelle que soit la sémantique de null. Vous pouvez utiliser une <select><option> liste déroulante pour sauver l'immobilier, mais l'utilisateur doit cliquer deux fois et les choix ne sont pas presque aussi instantanément clair.

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

le RadioButtonList, défini comme une extension nommée RadioButtonForSelectList, construit les boutons radio pour vous, y compris la valeur sélectionnée/cochée, et définit le <div class="RBxxxx"> de sorte que vous pouvez utiliser css pour faire votre radio les boutons vont horizontal (display: inline-block), vertical, ou à la table (display: inline-block; width: 100px;)

dans le modèle (j'utilise string, string pour la définition du dictionnaire comme exemple pédagogique. Vous pouvez utiliser 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());
}
}
6
répondu Jules Bartow 2012-05-03 00:27:03

pour moi la solution était de changer le modèle de vue. Considérez que vous êtes à la recherche de factures. Ces factures peuvent être payées ou non. Donc votre recherche a trois options: payé, non payé, ou "je M'en fous".

j'ai eu ce jeu à l'origine comme un bool? domaine:

public bool? PaidInvoices { get; set; }

Cela m'a fait tomber sur cette question. J'ai fini par créer un type Enum et j'ai géré cela comme suit:

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

bien sûr que je les ai fait envelopper étiquettes et avait le texte spécifié, je veux juste dire Voici une autre option à considérer.

3
répondu Paul 2013-11-08 16:32:05
La case à cocher

ne vous offre que 2 valeurs (vrai, faux). Nullable boolean a 3 valeurs (true, false, null) il est donc impossible de le faire avec une case à cocher.

une bonne option est d'utiliser un drop down à la place.

Modèle

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

contrôleur

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

Vue

@Html.DropDownListFor(m => m.myValue, valueList)
3
répondu Gudradain 2014-08-26 14:26:28

l'approche la plus propre que j'ai pu trouver est d'étendre les extensions disponibles à HtmlHelper tout en réutilisant les fonctionnalités fournies par le cadre.

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

j'ai expérimenté avec 'modeler' l'expression pour permettre un passage direct à l'indigène CheckBoxFor<Expression<Func<T, bool>>> mais je ne pense pas que ce soit possible.

3
répondu Red Taz 2016-06-09 08:58:43

j'ai eu un problème similaire dans le passé.

créer une case à cocher en HTML, et définir l'attribut name=" Foo " cela devrait toujours être affiché correctement.

<input type="checkbox" name="Foo" checked="@model.Foo.Value" /> Foo Checkbox<br />
1
répondu Chris Lucian 2012-06-16 16:21:41

je créerais en fait un template pour cela et j'utiliserais ce template avec un EditorFor().

Voici comment je l'ai fait:

  1. créer mon modèle, qui est essentiellement une vue partielle que j'ai créé dans le répertoire Editortmplates, sous partagé, sous vues l'appeler comme (par exemple): 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. utilisez - le comme ceci (en tout point de vue):

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

C'est tout.

Les modèles

sont si puissants dans MVC, utilisez-les.. Vous pouvez créer une page entière comme un modèle, que vous utiliseriez avec le @Html.EditorFor() ; à condition que vous passiez son modèle de vue dans l'expression lambda..

1
répondu Tarek Freijah 2015-12-07 15:21:34

il suffit de vérifier la valeur nulle et de retourner false:

@{ bool nullableValue = ((Model.nullableValue == null) || (Model.nullableValue == false)) ? false : true; }
@Html.CheckBoxFor(model => nullableValue)
0
répondu Rodrigo Boratto 2014-11-10 15:39:47

j'ai également fait face à la même question. J'ai essayé la méthode suivante pour résoudre le problème parce que je ne veux pas changer la base de données et générer à nouveau L'EDMX.

@{

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

 }

<label>@Html.CheckBoxFor(m => testVar)testVar</label><br />
0
répondu Amit Kumar 2014-12-22 09:04:20

lors de la réalisation d'un Éditortemplate pour un modèle qui contient un bool nul...

  • Diviser le nullable bool en 2 booléens:

    // 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; }
    
  • dans le modèle de l'éditeur:

    @Html.HiddenFor(m => m.FooIsNull)
    
    @if (Model.FooIsNull)
    {
        // Null means "checkbox is hidden"
        @Html.HiddenFor(m => m.FooCheckbox)
    }
    else
    {
        @Html.CheckBoxFor(m => m.FooCheckbox)
    }
    
  • Ne sont pas de publication de l'origine des biens Foo, parce que c'est maintenant calculé à partir de FooIsNull et FooCheckbox.

0
répondu 2016-02-12 08:55:09

toutes les réponses ci-dessus sont venues avec ses propres problèmes. La manière la plus facile/propre IMO est de créer un helper

MVC5 Rasoir

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

Utilisation

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

dans mon scénario, une case à cocher annulable signifie qu'un membre du personnel n'a pas encore posé la question au client, donc elle est enveloppée dans un .checkbox-nullable pour que vous puissiez utiliser le style approprié et aider l'utilisateur final à identifier qu'il ne s'agit pas de true ni false

CSS

.checkbox-nullable {
    border: 1px solid red;
    padding: 3px;
    display: inline-block;
}
0
répondu zanderwar 2016-07-01 04:50:34

méthodes D'Extension:

        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
répondu Jim 2017-08-09 11:00:34
@{  bool testVar = ((bool)item.testVar ? true : false); }
  @Html.DisplayFor(modelItem => testVar)
-1
répondu edrdesigner 2015-08-13 17:32:11

il s'agit d'une question ancienne, et les réponses existantes décrivent la plupart des solutions de rechange. Mais il y a une option simple, si vous avez bool? dans votre viewmodel, et vous ne vous souciez pas de null dans votre UI:

@Html.CheckBoxFor(m => m.boolValue ?? false);
-3
répondu Jeff Dege 2014-03-27 14:52:32