Поставте прапорець для логічного значення, що допускає допуск


97

Моя модель має логічне значення, яке повинно бути дозволеним

public bool? Foo
{
   get;
   set;
}

отже, у моєму Razor cshtml у мене є

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

хіба що це не працює. Так само як і кастинг за допомогою (bool). Якщо я це роблю

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

це не створює помилки, але не прив'язується до моєї моделі при розміщенні, а foo має значення null. Який найкращий спосіб відобразити Foo на сторінці та зв’язати його з моєю моделлю в дописі?



2
Цей потік ігнорує проблему, через яку я повинен мати змогу визначити нуль як 3-те значення. Подання форми з незакріпленим прапорцем та подання форми, де прапорець не відображався - це два різні сценарії, які необхідно враховувати.
DMulligan

Відповіді:


107

Я з ним працюю

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

а потім створити Boolean.cshtml у моїй папці EditorTemplates і залипати

@model bool?

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

всередині.


2
Працює для мене. Дякую!
Самуель

1
Під час роботи з типовими булевими типами, що дозволяють обнулятись, я використав цей '' '@ Html.CheckBoxFor (m => m.Foo.HasValue)' ''
Gaurav Aroraa

9
@GauravKumarArora Ви створюєте прапорець для HasValueвластивості, що дозволяє обнуляти , але не фактичного логічного значення. Це створить прапорець, незалежно від базового значення. Якщо значення NULL має значення, воно завжди буде істинним.
Сієрс

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
Інша перевага цього перед прийнятою відповіддю полягає в тому, що ви можете вирішити, чи має значення null прирівнюватися до true або false у кожному конкретному випадку, як це визначає логіка вашої програми, замість того, щоб мати єдине значення за замовчуванням у всій програмі (або зробити два редактори шаблони!).
ChrisFox

25

У мене bool? IsDisabled { get; set; }в Model. Вставлено, якщо в режимі перегляду.

<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
Не рекомендуйте давати оцінку, оскільки це гарна спроба, оскільки це може неправильно вказати іншим читачам, що відповідь корисна, коли у неї є проблеми.
Кріс,

Краще виглядає альтернатива - встановити для логічного значення значення false у контролері, якщо значення є нульовим, перед відтворенням сторінки, але все одно використовувати ідею .Value.
Грехем Лайт

15

Моя модель має логічне значення, яке повинно бути дозволеним

Чому? Це не має сенсу. Прапорець має два стани: позначений / не позначений або True / False, якщо хочете. Третя держава не існує.

Або зачекайте, що ви використовуєте моделі доменів у своїх поданнях замість моделей перегляду? Це ваша проблема. Тож рішення для мене полягає у використанні моделі подання, в якій ви визначите просту логічну властивість:

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

і тепер у вас буде дія вашого контролера передати цю модель подання у подання та сформувати відповідний прапорець.


26
Існує безліч різних причин, чому вхід foo може взагалі не відображатися на сторінці. Якщо воно з’являється, я можу припустити, що воно має значення, але мені потрібно мати можливість розрізнити, коли модель розміщується з foo як не позначений, і коли foo не відображається.
DMulligan

@KMulligan, а як щодо включення ще однієї логічної властивості до вашої моделі подання, яка вказує, чи слід відображати прапорець для властивості Foo і який можна зберігати у прихованому полі, щоб при поштовій передачі ви знали, чи слід враховувати значення Foo чи ні.
Дарін Димитров

Я робив це спочатку, але отримав тонни цих примітивних типів цінностей, які з різних причин можуть бути включені чи не включені в мої форми. Додавання булевих символів для всіх них почало почуватися безглуздо. Коли я погуглив нульові значення, я зрозумів, що це шлях.
DMulligan

4
@KMulligan, ти можеш писати помічники, шаблони редакторів, ... так що тобі не доведеться повторювати це для кожного властивості, яке має такі властивості.
Дарін Димитров

25
@ ДарінДімітров, ви чітко пропустили або проігнорували той факт, що ОП заявив, що він повинен бути здатним представити "нульовий" аспект булу. Ви повісили на тому, що він хотів скористатися CheckBoxFor. Замість того, щоб сказати йому, що він написав "поганий код", оскільки він використовував свою модель домену (що він, можливо, НЕ робив) і повідомляючи йому, що прапорці встановлені або не встановлені, ви повинні були спробувати відповісти на його запитання або не відповісти.
Andrew Steitz

7

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

Прапорець - це не те, що ви повинні використовувати - він насправді має лише один стан: Перевірено . Інакше це може бути що завгодно.

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

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

Для мене рішенням було змінити модель подання. Вважайте, що ви шукаєте рахунки-фактури. Ці рахунки можуть бути оплачені чи ні. Отже, ваш пошук має три варіанти: Платний, Неоплачений або "Мені все одно".

У мене це було спочатку встановлено як 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)

Звичайно, я їх загорнув у ярлики і вказав текст, я просто маю на увазі ось ще один варіант, який слід розглянути.


Це корисне подання. Якщо у вас обмежений простір, ви також можете досягти цього за допомогою розкривного меню / вибору, за винятком того, що для вибору опції потрібні два кліки. Як і у випадку з селектами, перемикачі можуть виглядати по-різному між браузерами, що може бути дизайнерським.
Savage

4

Прапорець пропонує лише 2 значення (true, false). Допустимий булевий значення має 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 лише за допомогою прапорця.
Дейв

@Dave Я думаю, ви повністю пропустили суть. В ОП бул? це означає, що йому потрібно вибрати одне з 3 можливих значень. Якщо він хотів мати лише істину чи хибність, він повинен використовувати bool, а не bool?
Gudradain

1
Насправді коментар OP вказує на протилежне - якщо у формі є прапорець, він взагалі не хоче, щоб null був опцією, оскільки ця опція охоплюється, коли існує інша форма без прапорця.
Дейв,

Я використовував цю саму стратегію на сторінці пошуку. Ви можете шукати Так, Ні або ігнорувати логічне значення у вашому пошуку. Там є варіант використання! : D
Джес

4

Я б насправді створив шаблон для нього і використав би цей шаблон за допомогою EditorFor ().

Ось як я це зробив:

  1. Створіть мій шаблон, який в основному є частковим поданням, яке я створив у каталозі 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;" />
  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

1

Раніше у мене була подібна проблема.

Створіть прапорець для введення в HTML і встановіть атрибут name = "Foo" Це все одно має розміщуватися належним чином.

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

Здається, це не публікується, я все ще втрачаю значення.
DMulligan

2
Це може мати проблеми з прив'язкою моделі
yoel halb

0

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

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

Ви знаєте, що метадані вашого майна будуть втрачені, правда? Клієнтська перевірка, назва поля, ідентифікатор тощо
T-moty

0

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

@{

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

 }

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

0

При створенні EditorTemplate для моделі, яка містить допуск, який може обнулятися ...

  • Розділіть обнулюваний 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.


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)

За моїм сценарієм, позначка, що допускає обнулення, означає, що співробітник ще не задав питання клієнту, тому він загорнутий .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і це успішно прив'язується до логічного значення, що допускає обнулення:

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


-4

Це старе запитання, і існуючі відповіді описують більшість альтернатив. Але є один простий варіант, якщо у вас є bool? у вашій viewmodel, і ви не дбаєте про нуль у вашому інтерфейсі:

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

2
Ви спробували це? Оскільки методи xxxFor очікують виразу члена, я б поставив добрі гроші, що це призведе до помилки виконання. Він намагається визначити цільову властивість або поле, на даний момент нічого не оцінюючи.
JRoughan,

2
Помилка часу виконання "Шаблони можна використовувати лише з польовим доступом, доступом до властивостей, одновимірним індексом масиву або однозначними виразами користувацького індексатора."
ePezhman
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.