Подтвердить что ты не робот

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)
4b9b3361

Ответ 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)
}