Сохранение выбранного значения в выпадающих списках MVC

StackOverflow https://stackoverflow.com/questions/1614923

Вопрос

Я новичок в MVC, но я прошел через все это, прочитал всю документацию, все вопросы и все записи в блогах, которые смог найти, и все, что я делаю, - это полностью оборачиваюсь вокруг оси.

Я пытаюсь выполнить действие "создать" и просмотреть.Мой ввод данных относительно прост и распространен:У меня есть выпадающий список и текстовое поле.В моем случае я создаю канал контактов с пользователем, и в раскрывающемся списке выбирается между электронной почтой и textmsg, а затем в текстовом поле вводится соответствующая контактная информация, либо правильно сформированный адрес электронной почты, либо номер мобильного телефона.

Вот (слегка упрощенная форма) моей страницы просмотра:

 <tr>
     <td><%= Html.DropDownList("ChannelDescription", Model.ChannelDescription, "Select a Channel", new { id = "ChannelDDL", onchange="ChannelDDLChanged()" })%>
         <br />
         <%= Html.ValidationMessage("ChannelDescription", "Please Select a Channel") %>
      </td>
      <td>
           <%= Html.TextBox("SubscriberNotificationAddr") %> <br />
           <%= Html.ValidationMessage("SubscriberNotificationAddr", "Please enter a contact address or number") %>
       </td>
  </tr>

Я использую строго типизированную модель ViewData, а не ViewDataDictionary .Элемент ChannelDescription представляет собой список выбора, который инициализируется списком вариантов без выделения.

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

Моя проблема заключается в том, что если данные содержат ошибку, такую как неверно сформированный адрес электронной почты или номер мобильного телефона, и я должен вернуться к просмотру, мне не удалось повторно отобразить выбор из выпадающего списка.Элемент ChannelDescription воссоздается в контроллере с выбором пользователя в качестве выбранного элемента.Я установил точки останова в этой строке представления и проверил, что выбранный элемент списка элементов имеет свойство Selected, равное true, но он по-прежнему отображает значение по умолчанию "Выбрать канал".

Похоже, что это была бы очень распространенная ситуация, и она не должна быть такой сложной.Что я делаю не так?

К вашему сведению, это с MVC 1.0 (выпуск), Windows 7 и VS 2008, работающий под управлением Firefox 3.5.2.

Это было полезно?

Решение 2

У меня были некоторые обсуждения с Брэдом Уилсоном, из команды MVC, и он объяснил мне, что я неправильно понимаю, как использовать вспомогательный метод DropDownList (недоразумение, которое я думаю, может быть довольно распространенным, из того, что я прочитал ).

В основном, EITHER присваивают ему SelectList в именованном параметре ViewModel и позволяют ему строить выпадающий список из этого списка с выбранными соответствующими элементами, ИЛИ дают ему SelectList в качестве отдельного параметра и позволяют именованному параметру ViewModel будет просто строкой значений для выбранного элемента (ов). Если вы зададите ему параметр SelectList, то он ожидает, что именованное значение будет строкой или списком строк, а НЕ SelectList.

Итак, теперь ваша ViewModel имеет два элемента для одного концептуального элемента в представлении (выпадающий список). Таким образом, у вас может быть модель, которая имеет

string SelectedValue {get; set;}
SelectList DropDownElements { get; set;}

Затем вы можете предварительно заполнить DropDownElements вариантами, но в привязке вида вашей модели вам просто нужно иметь дело с элементом SelectedValue. Мне кажется, это очень хорошо работает, когда я так делаю.

Другие советы

После просмотра приведенного выше ответа я захотел проверить это, потому что во всех примерах, которые я видел, действительно использовался ViewDataDictionary, а не строго типизированный ViewDataModel .

Поэтому я провел несколько экспериментов.Я создал очень простое представление, которое использовало обычный ViewDataDictionary и передавало значения с помощью именованных ключей.Выбранный элемент сохранялся просто отлично.Затем я вырезал и вставил это представление (и контроллер) в другое, изменив только то, что было необходимо для переключения на строго типизированную модель ViewData.О чудо, в нем также сохранился выбранный элемент.

Итак, чем еще отличался мой простой тест от моего приложения?В своем тесте я использовал просто "Html.DropDownList("name", "optionLabel")".Однако в моем приложении мне нужно было добавить атрибуты HTML, и единственные доступные перегрузки, которые включали htmlAttributes, также включают список выбора.

Оказывается, что перегрузка выпадающего списка параметром select list нарушена!Просматривая загруженный исходный код MVC, когда DropDownList вызывается только с именем или name и optionLabel, он в конечном итоге извлекает целевой список выбора из ViewData, а затем вызывает частный метод SelectInternal с помощью следующего вызова:

    return SelectInternal(htmlHelper, optionLabel, name, selectList, true /* usedViewData */, false /* allowMultiple */, (IDictionary<string, object>)null /* htmlAttributes */);

Однако, если он вызывается с параметром SelectList, он заканчивается следующим образом:

   return SelectInternal(htmlHelper, optionLabel, name, selectList, false /* usedViewData */, false /* allowMultiple */, htmlAttributes);

Разница в том, что в первом (который будет работать корректно) параметр "usedViewData" имеет значение true, в то время как во втором - значение false.Что на самом деле нормально, но выявляет внутренний дефект в процедуре SelectInternal.

Если usedViewData имеет значение false, он получает объектную переменную "defaultValue" из модели ViewData.Однако defaultValue используется так, как если бы это была либо строка, либо массив строк, когда на самом деле то, что возвращается из ViewData, является списком выбора.(IEnumerable<SelectListItem>).

Если usedViewData имеет значение true, то defaultValue будет либо нулевым, либо строковым.

Затем, если defaultValue не равно null, оно в конечном итоге переходит в блок кода, который содержит это:

        foreach (SelectListItem item in selectList) {
            item.Selected = (item.Value != null) ? selectedValues.Contains(item.Value) : selectedValues.Contains(item.Text);
            newSelectList.Add(item);

SelectList - это исходный список выбора, который был передан, поэтому элемент является SelectListItem (выбран текст строки, строковое значение и bool).Но SelectedValues был получен из defaultValue и становится списком SelectLists, а не списком строк.Таким образом, для каждого из элементов устанавливается флаг Selected в зависимости от того, "Содержит" ли список SelectedValues item.Value .Ну, список SelectLists никогда не будет "Содержать" строку, поэтому элемент.Выбранный никогда не будет установлен.(Исправление:на самом деле, после дополнительной трассировки с помощью отладчика я обнаружил, что SelectedValues является производным от defaultValue с помощью вызова "toString()".Таким образом, на самом деле это список строк, но вместо того, чтобы содержать нужные нам значения, он содержит "System.Web.Mvc.SelectList" - результат применения "toString()" к сложному объекту, такому как SelectList.Результат все тот же - мы не найдем искомое значение в этом списке.)

Затем он заменяет вновь созданный "newSelectList" на исходный "SelectList" и переходит к созданию HTML-кода на его основе.

Как сказал выше cagdas (я прошу прощения за то, что вырезал ваше имя, но я не знаю, как создать эти символы на моей клавиатуре в США), я думаю, мне придется создать свой собственный метод для использования вместо HtmlHelper выпадающего списка.Я полагаю, поскольку этот релиз 1 и релиз 2 находятся в бета-версии 2, мы не можем ожидать каких-либо исправлений ошибок, если не сделаем это сами, верно?

Кстати, если вы до сих пор следили за мной, этот код находится в src\SystemWebMvc \ Mvc \ Html\SelectExtensions.cs, примерно в строке 116-136

Да, у меня тоже было очень много проблем с тем, чтобы DropDownList уважал выбранный элемент, который я ему дал.

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

К вашему сведению, я перестал использовать этот метод HtmlHelper. Теперь я просто сам выводю теги <select> и <option> с помощью цикла и устанавливаю свойство selected тега option, проверяя его самостоятельно.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top