Привязка к списку выбора в MVC - PullRequest
11 голосов
/ 27 мая 2010

Еще раз я столкнулся с ситуацией "Это не должно быть? *! # Hard".

Проблема: я хочу использовать форму в MVC для создания объекта. Одним из элементов объекта является набор ограниченных вариантов - идеальный кандидат для выпадающего списка.

Но если я использую SelectList в моей модели и раскрывающийся список в моем представлении, а затем пытаюсь опубликовать модель обратно в мой метод Create, я получаю ошибку «Исключение отсутствующего метода: нет конструктора без параметров для этого объекта» ». Изучая исходный код MVC, выясняется, что для привязки к модели Binder должен сначала иметь возможность его создать, и он не может создать SelectList, поскольку для него нет конструктора по умолчанию.

Вот упрощенный код: Для модели:

public class DemoCreateViewModel
{
    public SelectList Choice { get; set; }
}

Для контроллера:

//
// GET: /Demo/Create

public ActionResult Create()
{
    DemoCreateViewModel data = new DemoCreateViewModel();
    data.Choice = new SelectList(new string[] { "Choice1", "Choice2", "Choice3" });
    ViewData.Model = data;
    return View();
}

//
// POST: /Demo/Create

[HttpPost]
public ActionResult Create(DemoCreateViewModel form)
{
    try
    {
        // TODO: Add insert logic here

        return RedirectToAction("Index");
    }
    catch
    {
        return View();
    }
}

А для просмотра:

<fieldset>
    <legend>Fields</legend>
    <%= Html.LabelFor(model => model.Choice) %>
    <%= Html.DropDownListFor(model => model.Choice, Model.Choice) %>
    <p>
        <input type="submit" value="Create" />
    </p>
</fieldset>

Теперь я знаю, что Я МОГУ СДЕЛАТЬ эту работу, отбросив 10 ярдов и сделав выбор: обойти привязку модели и вернуться к FormCollection, а также проверить и связать все поля самостоятельно, но должен быть более простой способ. Я имею в виду, что это примерно такое же простое требование, как и оно. Есть ли способ заставить это работать в архитектуре MVC ModelBinding? Если так, то, что это? А если нет, то почему?

Редактировать: Ну, у меня на лице яйцо, но, возможно, это поможет кому-то еще. Я провел еще несколько экспериментов и нашел простое решение, которое, кажется, работает.

Укажите простое значение (строка или целое число, в зависимости от типа значения в списке выбора) и назовите его как элемент модели, к которому вы привязываете. Затем укажите второй элемент в качестве списка выбора и назовите его как-нибудь еще. Итак, моя модель стала:

public class DemoCreateViewModel
{
    public string Choice { get; set; }
    public SelectList Choices { get; set; }
}

И тогда оператор DropDownListFor в представлении становится:

<%= Html.DropDownListFor(model => model.Choice, Model.Choices) %>

Когда я это делаю, кнопка отправки правильно связывает сделанный в форме выбор со строкой Выбор и отправляет модель обратно во второй метод Create.

Ответы [ 2 ]

5 голосов
/ 18 февраля 2011

Вот один подход:

@Html.DropDownListFor(model => model.Choice, 
                      ViewBag.Choices as SelectList, 
                      "-- Select an option--",
                      new { @class = "editor-textbox" })

Обратите внимание, что я использую ViewBag для хранения моего SelectList. Таким образом, когда вы отправляете сообщение обратно, клиент не отправляет весь список выбора на сервер как часть модели.

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

ViewBag.Choices = new SelectList(....
0 голосов
/ 09 апреля 2013

Рассмотрите возможность создания другой модели представления для действия публикации без свойства SelectList:

            public class DemoCreateViewModelForUpdate
            {
                public string Choice { get; set; }
            }

Затем вы всегда можете сопоставить экземпляр DemoCreateViewModelPost с экземпляром DemoCreateViewModel, если состояние модели недопустимо и вы хотите повторно отобразить представление. Я предпочитаю, чтобы все, что требуется для представления, было в моем классе модели представления дисплея, поэтому, используя отдельную модель представления только для обновления, я буду держать вещи тонкими и аккуратными для поездки обратно на сервер.

По вашему мнению, вы должны сделать:

            @Html.DropDownListFor(m => m.Choice, Model.Choices)

, как в предыдущем ответе, так что никакие ненужные данные не будут в оба конца.

...