ASP.NET MVC DropDownListДля выбора значения из модели
Я использую ASP.NET MVC 3 и просто запускаю "getcha" с помощью DropDownListFor
HTML Helper.
Я делаю это в своем контроллере:
ViewBag.ShippingTypes = this.SelectListDataRepository.GetShippingTypes();
И метод GetShippingTypes
:
public SelectList GetShippingTypes()
{
List<ShippingTypeDto> shippingTypes = this._orderService.GetShippingTypes();
return new SelectList(shippingTypes, "Id", "Name");
}
Причина, по которой я помещал ее в ViewBag
, а не в модели (у меня есть строго типизированные модели для каждого представления), заключается в том, что у меня есть коллекция элементов, которая отображает с помощью EditorTemplate, которая также должна иметь доступ к ShippingTypes выберите список.
В противном случае мне нужно пропустить всю коллекцию и назначить свойство ShippingTypes.
Пока все хорошо.
На мой взгляд, я делаю это:
@Html.DropDownListFor(m => m.RequiredShippingTypeId, ViewBag.ShippingTypes as SelectList)
(RequiredShippingTypeId
имеет тип Int32
)
Случается, что значение RequiredShippingTypeId
не выбрано в раскрывающемся списке.
Я наткнулся на это: http://web.archive.org/web/20090628135923/http://blog.benhartonline.com/post/2008/11/24/ASPNET-MVC-SelectList-selectedValue-Gotcha.aspx
Он предполагает, что MVC будет искать выбранное значение из ViewData
, когда список выбора находится из ViewData
. Я не уверен, что это так, потому что сообщение в блоге старое, и он говорит о бета-версии MVC 1.
Обходной путь, который решает эту проблему, заключается в следующем:
@Html.DropDownListFor(m => m.RequiredShippingTypeId, new SelectList(ViewBag.ShippingTypes as IEnumerable<SelectListItem>, "Value", "Text", Model.RequiredShippingTypeId.ToString()))
Я попытался не ToString
на RequiredShippingTypeId
в конце, что дает мне такое же поведение, как и раньше: ни один элемент не выбран.
Я думаю, что это проблема с типом данных. В конечном счете, помощник HTML сравнивает строки (в списке выбора) с Int32
(из RequiredShippingTypeId
).
Но почему он не работает при установке SelectList в ViewBag
- когда он отлично работает при добавлении его в модель и делает это внутри представления:
@Html.DropDownListFor(m => m.Product.RequiredShippingTypeId, Model.ShippingTypes)
Ответы
Ответ 1
Причина, по которой это не работает, объясняется ограничением помощника DropDownListFor
: он может вывести выбранное значение, используя выражение лямбда, переданное как первый аргумент , только если эта лямбда выражение - это простое выражение доступа к свойствам. Например, это не работает с выражениями доступа индексатора массива, который является вашим случаем из-за шаблона редактора.
У вас в основном есть (исключая шаблон редактора):
@Html.DropDownListFor(
m => m.ShippingTypes[i].RequiredShippingTypeId,
ViewBag.ShippingTypes as IEnumerable<SelectListItem>
)
Не поддерживается следующее: m => m.ShippingTypes[i].RequiredShippingTypeId
. Он работает только с простыми выражениями доступа к ресурсам, но не с индексированным доступом к коллекции.
Обходной путь, который вы нашли, является правильным способом решения этой проблемы, явно передавая выбранное значение при создании SelectList
.
Ответ 2
Это может быть глупо, но добавляет ли он к переменной в вашем представлении что-нибудь?
var shippingTypes = ViewBag.ShippingTypes;
@Html.DropDownListFor(m => m.Product.RequiredShippingTypeId, shippingTypes)
Ответ 3
Существует перегруженный метод для @html.DropdownList для обработки этого.
Существует альтернатива для установки выбранного значения в раскрывающемся списке HTML.
@Html.DropDownListFor(m => m.Section[b].State,
new SelectList(Model.StatesDropdown, "value", "text", Model.Section[b].State))
Мне удалось получить выбранное значение из модели.
"value", "text", Model.Section[b].State
в этом разделе приведенный выше синтаксис добавляет выбранный атрибут к значению, загруженному из контроллера
Ответ 4
вы можете создавать динамические viewdata вместо viewbag для каждого поля dropdownlist для сложного типа.
надеюсь, это даст вам подсказку, как это сделать
@if (Model.Exchange != null)
{
for (int i = 0; i < Model.Exchange.Count; i++)
{
<tr>
@Html.HiddenFor(model => model.Exchange[i].companyExchangeDtlsId)
<td>
@Html.DropDownListFor(model => model.Exchange[i].categoryDetailsId, ViewData["Exchange" + i] as SelectList, " Select category", new { @id = "ddlexchange", @class = "form-control custom-form-control required" })
@Html.ValidationMessageFor(model => model.Exchange[i].categoryDetailsId, "", new { @class = "text-danger" })
</td>
<td>
@Html.TextAreaFor(model => model.Exchange[i].Address, new { @class = "form-control custom-form-control", @style = "margin:5px;display:inline" })
@Html.ValidationMessageFor(model => model.Exchange[i].Address, "", new { @class = "text-danger" })
</td>
</tr>
}
}
Ответ 5
Я был просто поражен этим ограничением и разобрался с простым обходным решением. Только определенный метод расширения, который внутренне генерирует SelectList
с правильным выбранным элементом.
public static class HtmlHelperExtensions
{
public static MvcHtmlString DropDownListForEx<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
IEnumerable<SelectListItem> selectList,
object htmlAttributes = null)
{
var selectedValue = expression.Compile().Invoke(htmlHelper.ViewData.Model);
var selectListCopy = new SelectList(selectList.ToList(), nameof(SelectListItem.Value), nameof(SelectListItem.Text), selectedValue);
return htmlHelper.DropDownListFor(expression, selectListCopy, htmlAttributes);
}
}
Лучше всего, что это расширение можно использовать так же, как оригинал DropDownListFor
:
@for(var i = 0; i < Model.Items.Count(); i++)
{
@Html.DropDownListForEx(x => x.Items[i].CountryId, Model.AllCountries)
}