Связывание с SelectList в MVC
Снова я столкнулся с ситуацией "Это не должно быть! *! # жесткое".
Проблема: я хочу использовать форму в 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? Если так, то, что это? А если нет, то как?
Edit: Ну, у меня есть яйцо на моем лице, но, возможно, это поможет кому-то другому. Я сделал еще несколько экспериментов и нашел простое решение, которое, похоже, работает.
Укажите простое значение (строка или целое число, в зависимости от того, какой тип значения выбранного списка), и укажите имя как элемент модели, к которому вы привязываетесь. Затем укажите второй элемент в качестве списка выбора вариантов и назовите его чем-то другим. Итак, моя модель стала:
public class DemoCreateViewModel
{
public string Choice { get; set; }
public SelectList Choices { get; set; }
}
И затем оператор DropDownListFor в представлении становится:
<%= Html.DropDownListFor(model => model.Choice, Model.Choices) %>
Когда я это делаю, кнопка submit правильно привязывает выбор, сделанный в форме к строке Choice, и возвращает модель ко второму методу Create.
Ответы
Ответ 1
Вот один из подходов:
@Html.DropDownListFor(model => model.Choice,
ViewBag.Choices as SelectList,
"-- Select an option--",
new { @class = "editor-textbox" })
Обратите внимание, что я использую ViewBag для размещения моего SelectList. Таким образом, когда вы отправляете сообщение назад, клиент не отправляет весь список выбора до сервера как часть модели.
В вашем коде контроллера вам просто нужно установить сумку просмотра:
ViewBag.Choices = new SelectList(....
Ответ 2
Рассмотрите возможность создания другой модели представления для вашего действия post без свойства SelectList:
public class DemoCreateViewModelForUpdate
{
public string Choice { get; set; }
}
Затем вы всегда можете сопоставить экземпляр DemoCreateViewModelPost с экземпляром DemoCreateViewModel, если состояние модели недействительно и вы хотите повторно показать представление. Я предпочитаю все, что необходимо для представления, чтобы быть в моем классе модели отображения, поэтому, используя отдельную модель просмотра только для просмотра, позвольте мне сохранить все тонкие и аккуратные для поездки обратно на сервер.
По вашему мнению, вы бы сделали:
@Html.DropDownListFor(m => m.Choice, Model.Choices)
как и в предыдущем ответе, поэтому никакие ненужные данные не будут проходить в оба конца.