Группа флажков ASP.NET MVC - PullRequest
       7

Группа флажков ASP.NET MVC

12 голосов
/ 15 января 2010

Я пытаюсь сформулировать обходной путь для отсутствия «группы флажков» в ASP.NET MVC. Типичный способ реализовать это - иметь флажки с одинаковыми именами, каждое со значением, которое оно представляет.

<input type="checkbox" name="n" value=1 />
<input type="checkbox" name="n" value=2 />
<input type="checkbox" name="n" value=3 />

При отправке будет разделять запятыми все значения для элемента запроса "n" .. поэтому Request ["n"] == "1,2,3", если все три проверены при отправке В ASP.NET MVC вы можете иметь параметр n в качестве массива для принятия этого сообщения.

public ActionResult ActionName( int[] n ) { ... }

Все вышеперечисленное работает нормально. У меня проблема в том, что при сбое проверки флажки не возвращаются в их проверенное состояние. Любые предложения.

Код проблемы: (я начал с проекта asp.net mvc по умолчанию)

Контроллер

    public class HomeController : Controller
    {
        public ActionResult Index()
        {   var t = getTestModel("First");
            return View(t);
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Index(TestModelView t)
        {   if(String.IsNullOrEmpty( t.TextBoxValue))
                ModelState.AddModelError("TextBoxValue", "TextBoxValue required.");
            var newView = getTestModel("Next");
            return View(newView);
        }

        private TestModelView getTestModel(string prefix)
        {   var t = new TestModelView();
            t.Checkboxes = new List<CheckboxInfo>()
            {   new CheckboxInfo(){Text = prefix + "1", Value="1", IsChecked=false},
                new CheckboxInfo(){Text = prefix + "2", Value="2", IsChecked=false} 
            };
            return t;
        }
    }
    public class TestModelView
    {   public string TextBoxValue { get; set; }
        public List<CheckboxInfo> Checkboxes { get; set; }
    }
    public class CheckboxInfo
    {   public string Text { get; set; }
        public string Value { get; set; }
        public bool IsChecked { get; set; }
    }
}

ASPX

<%
using( Html.BeginForm() ){ 
%>  <p><%= Html.ValidationSummary() %></p>
    <p><%= Html.TextBox("TextBoxValue")%></p>
    <p><%  
    int i = 0;
    foreach (var cb in Model.Checkboxes)
    { %>
        <input type="checkbox" name="Checkboxes[<%=i%>]" 
            value="<%= Html.Encode(cb.Value) %>" <%=cb.IsChecked ? "checked=\"checked\"" : String.Empty %> 
            /><%= Html.Encode(cb.Text)%><br />
    <%      i++;
    } %></p>
    <p><input type="submit" value="submit" /></p>
<%
}
%>

Рабочий код

Контроллер

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(TestModelView t)
{
    if(String.IsNullOrEmpty( t.TextBoxValue))
    {   ModelState.AddModelError("TextBoxValue", "TextBoxValue required.");
        return View(t); 
    }
    var newView = getTestModel("Next");
    return View(newView);
}

ASPX

int i = 0;
foreach (var cb in Model.Checkboxes)
{ %>
    <input type="checkbox" name="Checkboxes[<%=i%>].IsChecked" <%=cb.IsChecked ? "checked=\"checked\"" : String.Empty %> value="true" />
    <input type="hidden"   name="Checkboxes[<%=i%>].IsChecked" value="false" />
    <input type="hidden" name="Checkboxes[<%=i%>].Value" value="<%= cb.Value %>" />
    <input type="hidden" name="Checkboxes[<%=i%>].Text" value="<%= cb.Text %>" />
    <%= Html.Encode(cb.Text)%><br />
<%      i++;
} %></p>
<p><input type="submit" value="submit" /></p>

Конечно, нечто подобное можно сделать с помощью Html Helpers, но это работает.

Ответы [ 5 ]

6 голосов
/ 27 апреля 2010

Вот окончательное решение:

public static class Helpers
{
    public static string CheckboxGroup<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> propertySelector, int value) where TProperty: IEnumerable<int>
    {
        var groupName = GetPropertyName(propertySelector);
        var modelValues = propertySelector.Compile().Invoke(htmlHelper.ViewData.Model);

        var svalue = value.ToString();
        var builder = new TagBuilder("input");
        builder.GenerateId(groupName);
        builder.Attributes.Add("type", "checkbox");
        builder.Attributes.Add("name", groupName);
        builder.Attributes.Add("value", svalue);
        var contextValues = HttpContext.Current.Request.Form.GetValues(groupName);
        if ((contextValues != null && contextValues.Contains(svalue)) || (modelValues != null && modelValues.Contains(value)))
        {
            builder.Attributes.Add("checked", null);
        }
        return builder.ToString(TagRenderMode.Normal);
    }

    private static string GetPropertyName<T, TProperty>(Expression<Func<T, TProperty>> propertySelector)
    {
        var body = propertySelector.Body.ToString();
        var firstIndex = body.IndexOf('.') + 1;
        return body.Substring(firstIndex);
    }
}

А на ваш взгляд:

                        <%= Html.CheckboxGroup(model => model.DocumentCoverCustom, "1")%>(iv),<br />
                        <%= Html.CheckboxGroup(model => model.DocumentCoverCustom, "2")%>(vi),<br />
                        <%= Html.CheckboxGroup(model => model.DocumentCoverCustom, "3")%>(vii),<br />
                        <%= Html.CheckboxGroup(model => model.DocumentCoverCustom, "4")%>(ix)<br />
6 голосов
/ 15 января 2010

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

<%= Html.CheckBox("n[0]") %><%= Html.Hidden("n[0]",false) %>
<%= Html.CheckBox("n[1]") %><%= Html.Hidden("n[1]",false) %>
<%= Html.CheckBox("n[2]") %><%= Html.Hidden("n[2]",false) %>

Скрытые поля необходимы, потому что если флажок не установлен, форма не отправляет никакого значения. Со скрытым полем отправляет false.

Ваш метод публикации будет:

[HttpPost]
public ActionResult Test(bool[] n)
{
    return View();
}

Это не может быть оптимальным, и я открыт для комментариев, но это работает:)

EDIT

Расширенная версия:

<%= Html.CheckBox("n[0].Checked") %><%= Html.Hidden("n[0].Value",32) %><%= Html.Hidden("n[0].Checked",false) %>
<%= Html.CheckBox("n[1].Checked") %><%= Html.Hidden("n[1].Value",55) %><%= Html.Hidden("n[1].Checked",false) %>
<%= Html.CheckBox("n[2].Checked") %><%= Html.Hidden("n[2].Value",76) %><%= Html.Hidden("n[2].Checked",false) %>

Ваш метод публикации будет:

[HttpPost]
public ActionResult Test(CheckedValue[] n)
{
    return View();
}

public class CheckedValue
{
     public bool Checked { get; set; }
     public bool Value { get; set; }
}

Я написал это без VS, так что, возможно, потребуется небольшое исправление.

1 голос
/ 21 июля 2010

Это решение может быть интересным для тех, кто хочет чистый / простой подход: Поддерживать состояние динамического списка флажков в ASP.NET MVC

Я бы не советовал использовать Html.CheckBox, если у вас нет супер простого одиночного флажка, привязанного к одному bool (или максимум к паре статических). Когда вы начинаете иметь списки флажков в одном массиве или динамические флажки, с ними трудно работать, и вы в конечном итоге программируете весь мир на раздутой стороне сервера, чтобы справиться с недостатками и заставить все работать. Забудьте об этом, и просто используйте вышеупомянутое чистое решение, ориентированное на HTML, и вы быстро приступите к работе с меньшими затратами на обслуживание в будущем.

1 голос
/ 15 января 2010

Ну ... флажки сами по себе не будут знать их состояния, особенно если вы не используете помощник Html.CheckBox (если это так, смотрите ответ LuKLed). Вам нужно будет поместить проверенное состояние каждого поля в ваши ViewData (или Model), а затем выполнить поиск в вашем View тем или иным способом.

Предупреждение: действительно ужасный проверочный код:

Контроллер:

//validation fails
ViewData["checkboxn"] = n;
return View();

Вид:

<% int[] n = (int[])ViewData["checkboxn"]; %>
<input type="checkbox" name="n" value=1 <%= n != null && n.Contains(1) ? "checked=\"checked\"" : "" %> />
<input type="checkbox" name="n" value=2 <%= n != null && n.Contains(2) ? "checked=\"checked\"" : "" %> />
<input type="checkbox" name="n" value=3 <%= n != null && n.Contains(3) ? "checked=\"checked\"" : "" %> />

Все, что я здесь делаю, это передаю массив n обратно в представление, и, если он содержит значение для соответствующего флажка, добавление checked="checked" к элементу.

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

0 голосов
/ 17 июня 2016

Я знаю, что это должно быть безумно поздно, но только если кто-то еще окажется здесь ...

У MVC есть способ обрабатывать группы флажков.

в вашей модели представления:

[Показать (Имя = "Какие кредитные карты принимаются:")]

открытая строка [] EmployeeRoles {get;задавать;}

На вашей странице:

            <input id="EmployeeRoles" name="EmployeeRoles" type="checkbox" value="Supervisor" 
            @(Model.EmployeeRoles != null && Model.EmployeeRoles.Contains("Supervisor") ? "checked=true" : string.Empty)/>
            &nbsp;<span>Supervisor</span><br />

            <input id="EmployeeRoles" name="EmployeeRoles" type="checkbox" value="Auditor" 
            @(Model.EmployeeRoles != null && Model.EmployeeRoles.Contains("Auditor") ? "checked=true" : string.Empty)/>
            &nbsp;<span>Auditor</span><br />

            <input id="EmployeeRoles" name="EmployeeRoles" type="checkbox" value="Administrator" 
            @(Model.EmployeeRoles != null && Model.EmployeeRoles.Contains("Administrator") ? "checked=true" : string.Empty) />
            &nbsp;<span>Administrator</span>

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

    public static HtmlString CheckboxGroup<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> propertySelector, Type EnumType)
    {
        var groupName = GetPropertyName(propertySelector);
        var modelValues = ModelMetadata.FromLambdaExpression(propertySelector, htmlHelper.ViewData).Model;//propertySelector.Compile().Invoke(htmlHelper.ViewData.Model);

        StringBuilder literal = new StringBuilder();  

        foreach (var value in Enum.GetValues(EnumType))
        {
            var svalue = value.ToString();
            var builder = new TagBuilder("input");
            builder.GenerateId(groupName);
            builder.Attributes.Add("type", "checkbox");
            builder.Attributes.Add("name", groupName);
            builder.Attributes.Add("value", svalue);
            var contextValues = HttpContext.Current.Request.Form.GetValues(groupName);
            if ((contextValues != null && contextValues.Contains(svalue)) || (modelValues != null && modelValues.ToString().Contains(svalue)))
            {
                builder.Attributes.Add("checked", null);
            }

            literal.Append(String.Format("</br>{1}&nbsp;<span>{0}</span>", svalue.Replace('_', ' '),builder.ToString(TagRenderMode.Normal)));
        }

        return (HtmlString)htmlHelper.Raw(literal.ToString()); 
    }

    private static string GetPropertyName<T, TProperty>(Expression<Func<T, TProperty>> propertySelector)
    {
        var body = propertySelector.Body.ToString();
        var firstIndex = body.IndexOf('.') + 1;
        return body.Substring(firstIndex);
    }

на своей странице используйте его следующим образом: @ Html.CheckboxGroup (m => m.EmployeeRoles, typeof (Enums.EmployeeRoles))

Я использую enum, но вы можете использоватьлюбая коллекция

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...