Флажок для nullable boolean

Моя модель имеет логическое значение, которое должно быть равно NULL

public bool? Foo
{
   get;
   set;
}

поэтому в моем Razor cshtml у меня есть

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

за исключением того, что не работает. Также не бросает его (bool). Если я делаю

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

который не создает ошибку, но не привязывается к моей модели при публикации, а foo имеет значение null. Каков наилучший способ отображения Foo на странице и привязать его к моей модели в сообщении?

Ответ 1

Я получил его для работы с

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

а затем создав Boolean.cshtml в моей папке EditorTemplates и придерживаясь

@model bool?

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

внутри.

Ответ 2

Найден ответ в подобном вопросе - Рендеринг Nullable Bool как CheckBox. Это очень просто и просто работает:

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

Это как принятый ответ от @afinkelstein, за исключением того, что нам не нужен специальный шаблон редактора

Ответ 3

У меня есть 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> 

Ответ 4

Моя модель имеет логическое значение, которое должно быть равно NULL

Почему? Это не имеет смысла. Флажок имеет два состояния: отмечен/не установлен, или True/False, если хотите. Третьего государства нет.

Или подождите, пока вы используете модели своего домена в своих представлениях вместо просмотра моделей? Это ваша проблема. Поэтому решение для меня - использовать модель представления, в которой вы определяете простое логическое свойство:

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

и теперь у вас будет действие вашего контроллера, чтобы передать эту модель представления в представление и создать соответствующий флажок.

Ответ 5

Упрощение примитива со скрытыми полями, чтобы выяснить, не рекомендуется ли False или Null.

Флажок не то, что вы должны использовать - на нем действительно только одно состояние: Проверено. В противном случае это может быть что угодно.

Когда поле базы данных является нулевым логическим (bool?), UX должен использовать 3-радио кнопки, где первая кнопка представляет ваш "Проверено", вторая кнопка представляет "Не проверено", а третья кнопка представляет ваш 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, чтобы ваши переключатели переключались горизонтально (дисплей: inline- блок), вертикальный или в виде таблицы (дисплей: встроенный блок, ширина: 100 пикселей;)

В модели (я использую строку, строку для определения словаря в качестве педагогического примера. Вы можете использовать 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

Флажок содержит только 2 значения (true, false). Nullable boolean имеет 3 значения (true, false, null), поэтому это невозможно сделать с помощью флажка.

Хорошим вариантом является использование выпадающего списка.

Model

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

Для меня решение заключалось в изменении модели представления. Подумайте, что вы ищете счета-фактуры. Эти счета-фактуры могут быть оплачены или нет. Таким образом, ваш поиск имеет три варианта: "Платный", "Неоплаченный" или "Я не забочусь".

У меня это было первоначально как 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)

Конечно, я их обернул в ярлыки и указал текст, я просто имею в виду здесь другой вариант для рассмотрения.

Ответ 8

Я бы создал шаблон для него и использовал этот шаблон с помощью EditorFor().

Вот как я это сделал:

  • Создайте свой шаблон, который в основном является частичным представлением, созданным мной в каталоге 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;" />
    
  • Используйте его так (в любом представлении):

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

Вот и все.

Шаблоны настолько мощные в MVC, что их используют. Вы можете создать целую страницу как шаблон, который вы бы использовали с @Html.EditorFor(); при условии, что вы передадите свою модель представления в выражении лямбда.

Ответ 9

Самый чистый подход, который я мог бы предложить, - расширить расширения, доступные для 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>>>, но я не думаю, что это возможно.

Ответ 10

У меня была аналогичная проблема в прошлом.

Создайте флажок в HTML-блоке и установите атрибут name= "Foo". Это должно быть правильно опубликовано.

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

Ответ 11

Просто проверьте нулевое значение и верните ему false:

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

Ответ 12

Я также столкнулся с той же проблемой. Я попробовал следующий подход для решения проблемы потому что я не хочу менять БД и снова генерировать EDMX.

@{

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

 }

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

Ответ 13

При создании EditorTemplate для модели, содержащей nullable bool...

  • Разделите nullable 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.

Ответ 14

Все приведенные выше ответы принесли свои проблемы. Самый простой/чистый способ ИМО - создать помощника

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

Ответ 15

Методы расширения:

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

Ответ 16

ты можешь попробовать вот так

@Html.TextBoxFor(m => m.foo, new {   type = "checkbox" })

Ответ 17

Радиокнопки полезны, но они не позволяют отменить выбор. Если вы хотите такое поведение, тогда рассмотрите возможность использования раскрывающегося списка/выбора. Следующий код сгенерирует 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");
}

Ответ 18

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

Ответ 19

Это старый вопрос, и существующие ответы описывают большинство альтернатив. Но есть ли один простой вариант, если у вас есть bool? в вашей модели просмотра, и вы не заботитесь об нуле в пользовательском интерфейсе:

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