MVC 2 - Передача перечисления в CheckBoxFor - PullRequest
7 голосов
/ 16 ноября 2010

Предположим, у нас есть модель:

public class Document
{
    public string Name { get; set;}
    public List<DayOfWeek> WeekDays { get; set; }
}

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

Я имею в виду, что оно работает с CheckBoxFor(model=> model.SomeProperty), но не работает, если SomeProperty равно List<DayOfWeek>.DayOfWeek вот перечисление.

Заранее спасибо.

Ответы [ 5 ]

18 голосов
/ 16 ноября 2010

Это потребует изменения в вашем перечислении DayOfWeek, но я предпочитаю делать это как флаг (менее грязный, только одно значение и т. Д.). Интересно, что Microsoft также использует дни недели в документации enum flags .

Перечисление DayOfWeek с использованием битовых флагов:

[Flags]//<-- Note the Flags attribute
public enum DayOfWeek
{
  Monday = 1,
  Tuesday = 2,
  Wednesday = 4,
  Thursday = 8,
  Friday = 16,
  Saturday = 32,
  Sunday = 64,
}

Модель:

public class Document
{
  public string Name { get; set;}

  //Note that WeekDays is no longer a collection.
  public DayOfWeek WeekDays { get; set; }
}

Вид:

<% foreach(DayOfWeek dayOfWeek in Enum.GetValues(typeof(DayOfWeek))) { %>
  <label>
    <!-- The HasFlag stuff is optional and is just there to show how it would be populated if you're doing a `GET` request. -->
    <input type="checkbox" name="WeekDays[]" value="<%= (int)dayOfWeek%>" <%= Model.WeekDays.HasFlag(dayOfWeek) ? "checked='checked'" : "" %>" />
    <%= dayOfWeek %>
  </label>
<% } %>

Контроллер:

[HttpPost]
public ActionResult MyPostedPage(MyModel model)
{
  //I moved the logic for setting this into a helper because this could be re-used elsewhere.
  model.WeekDays = Enum<DayOfWeek>.ParseToEnumFlag(Request.Form, "WeekDays[]");
  ...
}

Быстрый помощник для ParseToEnumFlag:

public static class Enum<T>
{
  public static T ParseToEnumFlag(NameValueCollection source, string formKey)
  {
    //MVC 'helpfully' parses the checkbox into a comma-delimited list. We pull that out and sum the values after parsing it back into the enum.
    return (T)Enum.ToObject(typeof(T), source.Get(formKey).ToIEnumerable<int>(',').Sum());
  }
}

Справка: Причина, по которой значения флагов перечисления находятся в геометрическом ряду ( 1,2,4,8 ... ), заключается в том, что при сложении значений существует только одна возможная комбинация. Например, мы бы знали, что 31 могут быть только Пн, Вт, Ср, Тур и Пт (1 + 2 + 4 + 8 + 16).

Обновление - 3 сентября 2012

Кажется, я пропустил ToIEnumerable (), который является расширением в нашем исходном коде. Он принимает строку с разделителями и преобразует ее в IEnumerable, поэтому он идеально подходит для чисел с разделителями-запятыми. Спасибо @ escist за заголовок.

public static IEnumerable<T> ToIEnumerable<T>(this string source, char delimiter)
{
  return source.Split(new char[] { delimiter }, StringSplitOptions.RemoveEmptyEntries).Select(x => (T)Convert.ChangeType(x, typeof(T)));
}
12 голосов
/ 16 ноября 2010

Вы можете перечислить значения перечисления и вручную создать флажки.Использование одного и того же name для каждого флажка отправит их в виде массива в ActionMethod.

<% foreach(var value in Enum.GetValues(typeof(DayOfWeek))) { %>
     <% var name = Enum.GetName(typeof(DayOfWeek), value); %>
     <label for="dayofweek<%=value %>"><%=name %></label>
     <input type="checkbox" id="dayofweek<%=value %>" name="dayofweek" value="<%=value %>" />
<% } %>

Ваш метод действия будет выглядеть примерно так:

public ActionResult Save(DayOfWeek[] dayofweek)
{
     // Do Stuff
}
1 голос
/ 11 марта 2013

Основываясь на великолепном ответе Дэна Аткинсона, я сделал несколько ярлыков тут и там.Я бы предложил:

То же самое перечисление с [Flags] и моделью .

Для Просмотр , я бы не стал менять тип на int, но оставьте значения флажков string:

<input type="checkbox" name="WeekDays[]" 
       value="<%= dayOfWeek %>" 
       <%= Model.WeekDays.HasFlag(dayOfWeek) ? "checked='checked'" : "" %>" />

, что делает Controller намного проще:

[HttpPost]
public ActionResult MyPostedPage(MyModel model)
{
    string days = Request.Form.get("WeekDays[]");
    if (days == null) {
        model.WeekDays = 0;  // Depending whether you allow neither day to be selected
                             // you can handle this differently
    } else {
        model.WeekDays = (WeekDays)Enum.Parse(typeof(WeekDays), days);
    }

    ...
 }

Обратите внимание, код не использует расширенияна всех.

Ура,

1 голос
/ 09 июня 2012

Примечание: у меня была проблема с реализацией ответа Дэна с использованием HasFlag() в представлении при использовании dayOfWeek, объявленного как var. Я должен был объявить это как DayOfWeek Enum.

Вид:

<% foreach(DayOfWeek dayOfWeek in Enum.GetValues(typeof(DayOfWeek))) { %>
  <label>
    <!-- The HasFlag stuff is optional and is just there to show how it would be populated if you're doing a `GET` request. -->
    <input type="checkbox" name="WeekDays[]" value="<%= (int)dayOfWeek%>" <%= Model.WeekDays.HasFlag(dayOfWeek) ? "checked='checked'" : "" %>" />
    <%= dayOfWeek %>
  </label>
<% } %>

У меня также были проблемы с ToIEnumerable в помощнике, так как нет функции с таким именем (по крайней мере, для меня).

1 голос
/ 16 ноября 2010

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

Вот как вы могли бы встроить его в свой взгляд:

<% foreach(var dayOfWeek in Model.WeekDays) { %>
    <%= dayOfWeek.ToString() %><%= Html.CheckBox(dayOfWeek.ToString()) %>
<% } %>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...