DropDownListДля несоблюдения выбранного свойства SelectList

У меня есть следующая строка кода:

@Html.DropDownListFor(x => x.TimeOption, new SelectList(Model.TimeOptions, "Value", "Name", (int)Model.TimeOption))

Выпадающее меню правильно построено, а Selected действительно верно, но MVC не будет рисовать выпадающий список с правильным выбранным элементом. Разметка не выводит выбранный атрибут для параметра.

Результат выводится как:

<option value="0">Past Day</option>
<option value="1">Past Week</option>
<option value="2">Past Month</option>
<option value="3">Past Year</option>
<option value="4">Start of Time</option>

Однако, если вы посмотрите на прикрепленный снимок экрана, вы увидите, что он правильно выбран:

Watch list

Это влияет только на GET, а не на POST. Идеи?

Ответ 1

Это имеет тенденцию сильно культивировать людей - видимо, дорожная карта для MVC 5 содержит более интуитивные помощники DropDownList.

Когда вы выполните:

@Html.DropDownListFor(x => x.TimeOption ...)

... HTML-помощник сделает все возможное, чтобы не использовать значение, установленное в Selected = true, в SelectList. Он будет:

  • Попробуйте получить его из ModelState - который он не получит по запросу GET
  • Попробуйте получить его из ViewData - который он получит, потому что у вас есть свойство TimeOption на вашей модели.

Только если обе эти попытки потерпят неудачу, они будут поддаваться и использовать то, что вы просили использовать.

Итак, в вашем случае оно будет использовать текущее значение TimeOption для вашей модели в качестве выбранного значения. Что должно быть хорошо, потому что все, что вы просили в своем SelectList в любом случае ((int)Model.TimeOption), правильно?

Неправильно. Потому что он не будет передавать ваше свойство (enum?) В int, как вы. Он преобразует его в строку. Для enum, который дает имя перечисления - например. PastMonth. Если TimeOption является вашим собственным классом, это будет результат ToString().

Затем, когда он не находит эту строку в качестве одного из ваших значений <select> (потому что все они целые), он решает не делать ничего выбранного.

Короче: SelectListItem.Selected не влияет на помощника. Если ваш вспомогательный вызов указывает имя (буквально или через выражение лямбда), помощник будет использовать что-либо в ModelState или ViewData с этим именем и преобразовать его в строку.

В большинстве случаев это происходит с перечислениями. Самый простой способ обойти это - использовать имя перечисления, а не его int-представление, как значение для SelectListItem.

Ответ 2

У вас уже есть хорошее объяснение, почему он не работает, но просто чтобы добавить мой 2p

Как правило, я предпочитаю использовать перечисление SelectListItems в качестве источника dropdownitems, хотя и должен работать. Это предпочтительнее, так как нет необходимости указывать, какой элемент выбран - помощник MVC выведет его из того, кто Value соответствует методу TimeOption.ToString().

т

@Html.DropDownListFor(x => x.TimeOption, ((IEnumerable<TimeOption>)Model.TimeOptions).ToList().ConvertAll(y => new SelectListItem(){Text = y.Name, Value = y.Value.ToString()})

NB - я не уверен, какой тип Model.TimeOptions здесь - если его не IEnumerable <TimeOption> затем замените его. (если его уже есть список, то .ToList() не требуется)