Подтвердить что ты не робот

MVC3 EditorTemplate для обнуляемого булеана с помощью RadioButtons

У меня есть свойство на одном из моих объектов, которое является нулевым логическим, я хочу, чтобы моя логика имела значение true, да, false - No и null для N/A. Теперь, поскольку я собираюсь иметь несколько свойств, подобных этому на многих разных объектах, имеет смысл сделать редактор и отобразить шаблоны для этих свойств. Я собираюсь использовать jQuery UI, чтобы применить визуальный элемент набора кнопок после того, как все это работает, но на данный момент это выходит за рамки моей проблемы. Мой шаблон редактора выглядит следующим образом.

@model bool?
<div data-ui="buttonset">
@Html.RadioButtonFor(x => x, true, new { id = ViewData.TemplateInfo.GetFullHtmlFieldId("") + "Yes"}) <label for="@(ViewData.TemplateInfo.GetFullHtmlFieldId(""))Yes">Yes</label>
@Html.RadioButtonFor(x => x, false, new { id = ViewData.TemplateInfo.GetFullHtmlFieldId("") + "No" }) <label for="@(ViewData.TemplateInfo.GetFullHtmlFieldId(""))No">No</label>
@Html.RadioButtonFor(x => x, "null", new { id = ViewData.TemplateInfo.GetFullHtmlFieldId("") + "NA" }) <label for="@(ViewData.TemplateInfo.GetFullHtmlFieldId(""))NA">N/A</label>
</div>

Моя проблема заключается в том, что ни при каких обстоятельствах я не могу заставить этот шаблон редактора правильно отображать текущее значение модели. Поскольку я не предоставляю свойство модели в этой области, но сама модель, встроенная логика в MVC3 не будет корректно устанавливать проверенное свойство из-за проверки, сделанной для проверки того, что имя не пустое или пустое (см. MVC3 source, InputExtensions.cs: строка # 259). Я не могу установить проверенный атрибут динамически, сравнивая его с моделью, потому что браузер проверяет радиокассету на наличие проверенного атрибута, а не на значение, поэтому, хотя мои переключатели будут выглядеть следующим образом, последний остается выбранным.

<div class="span-4" data-ui="buttonset">
<input checked="checked" id="MyObject_BooleanValueYes" name="MyObject.BooleanValue" type="radio" value="True" /><label for="MyObject_BooleanValueYes">Yes</label>
<input checked="" id="MyObject_BooleanValueNo" name="MyObject.BooleanValue" type="radio" value="False" /><label for="MyObject_BooleanValueNo">No</label>
<input checked="" id="MyObject_BooleanValueNA" name="MyObject.BooleanValue" type="radio" value="null" /><label for="MyObject_BooleanValueNA">N/A</label>
</div><span class="field-validation-valid" data-valmsg-for="MyObject.BooleanValue" data-valmsg-replace="true"></span>&nbsp;</div>

Я не могу условно добавить HtmlAttribute, используя что-то вроде if?truevalue:falsevalue, потому что истинные/ложные части будут иметь разные анонимные типы, и я получаю сообщение об ошибке.

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

4b9b3361

Ответ 1

@model bool?
<div data-ui="buttonset">
@{
    Dictionary<string, object> yesAttrs = new Dictionary<string, object>(); 
    Dictionary<string, object> noAttrs = new Dictionary<string, object>(); 
    Dictionary<string, object> nullAttrs = new Dictionary<string, object>(); 

    yesAttrs.Add("id", ViewData.TemplateInfo.GetFullHtmlFieldId("") + "Yes");
    noAttrs.Add("id", ViewData.TemplateInfo.GetFullHtmlFieldId("") + "No");
    nullAttrs.Add("id", ViewData.TemplateInfo.GetFullHtmlFieldId("") + "NA");

    if (Model.HasValue && Model.Value)
    {
        yesAttrs.Add("checked", "checked");
    }
    else if (Model.HasValue && !Model.Value)
    {
        noAttrs.Add("checked", "checked");
    }
    else
    {
        nullAttrs.Add("checked", "checked");
    }
}

@Html.RadioButtonFor(x => x, "true", yesAttrs) <label for="@(ViewData.TemplateInfo.GetFullHtmlFieldId(""))Yes">Yes</label>
@Html.RadioButtonFor(x => x, "false", noAttrs) <label for="@(ViewData.TemplateInfo.GetFullHtmlFieldId(""))No">No</label>
@Html.RadioButtonFor(x => x, "null", nullAttrs) <label for="@(ViewData.TemplateInfo.GetFullHtmlFieldId(""))NA">N/A</label>
</div>

Ответ 2

Как насчет некоторого метода расширения, чтобы сохранить эту "одну строку, чтобы управлять ими всеми".: -)

public static class DictionaryHelper
{
    // This returns the dictionary so that you can "fluently" add values
    public static IDictionary<TKey, TValue> AddIf<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, bool addIt, TKey key, TValue value)
    {
        if (addIt)
            dictionary.Add(key, value);
        return dictionary;
    }
}

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

@model bool?
<div data-ui="buttonset">
@Html.RadioButtonFor(x => x, true, new Dictionary<string,object>()
    .AddIf(true, "id", ViewData.TemplateInfo.GetFullHtmlFieldId("") + "Yes")
    .AddIf(Model.HasValue && Model.Value, "checked", "checked")
) <label for="@(ViewData.TemplateInfo.GetFullHtmlFieldId(""))Yes">Yes</label>

@Html.RadioButtonFor(x => x, false, new Dictionary<string,object>()
    .AddIf(true, "id", ViewData.TemplateInfo.GetFullHtmlFieldId("") + "No")
    .AddIf(Model.HasValue && !Model.Value, "checked", "checked")
) <label for="@(ViewData.TemplateInfo.GetFullHtmlFieldId(""))No">No</label>

@Html.RadioButtonFor(x => x, "null", new Dictionary<string,object>()
    .AddIf(true, "id", ViewData.TemplateInfo.GetFullHtmlFieldId("") + "NA")
    .AddIf(!Model.HasValue, "checked", "checked")
) <label for="@(ViewData.TemplateInfo.GetFullHtmlFieldId(""))NA">N/A</label>
</div>

Ответ 3

Вам просто нужно обработать специальный нулевой случай:

<label class="radio">
  @Html.RadioButtonFor(x => x.DefaultBillable, "", new { @checked = !this.Model.DefaultBillable.HasValue })
  Not set
</label>
<label class="radio">
  @Html.RadioButtonFor(x => x.DefaultBillable, "false")
  Non-Billable
</label>
<label class="radio">
  @Html.RadioButtonFor(x => x.DefaultBillable, "true")
  Billable
</label>

Ответ 4

Проблема заключается в том, что вам нужно установить атрибут checked, потому что Html.RadioButtonFor не проверяет переключатель на основе nullable bool (что кажется недостатком).

Также, помещая радиоклетки внутри тега метки, вы можете выбрать значение, щелкнув метку.

Общий /EditorTemplates/Boolean.cshtml

@model bool?
<label>
    <span>n/a</span>
    @Html.RadioButtonFor(x => x, "", !Model.HasValue ? new { @checked=true } : null) 
</label>
<label>
    <span>Yes</span>
    @Html.RadioButtonFor(x => x, true, Model.GetValueOrDefault() ? new { @checked = true } : null)
</label>
<label>
    <span>No</span>
    @Html.RadioButtonFor(x => x, false, Model.HasValue && !Model.Value ? new { @checked = true } : null)
</label>

Ответ 5

Вы можете использовать @helper для упрощения принятого ответа:

@model bool?

<div data-ui="buttonset">
    @Radio(true,  "Yes", "Yes")
    @Radio(false, "No",  "No")
    @Radio(null,  "N/A", "NA")
</div>

@helper Radio(bool? buttonValue, string buttonLabel, string buttonId)
{
    Dictionary<string, object> attrs = new Dictionary<string, object>(); 

    // Unique button id
    string id = ViewData.TemplateInfo.GetFullHtmlFieldId("") + buttonId;

    attrs.Add("id", id);

    // Check the active button
    if (Model == buttonValue)
    {
        attrs.Add("checked", "checked");
    }

    @Html.RadioButtonFor(m => m, buttonValue, attrs) <label for="@id">@buttonLabel</label>
}