ASP.NET MVC MultiSelectList с неправильно выбранными значениями - PullRequest
26 голосов
/ 17 сентября 2010

Я знаю, что другие задавали этот вопрос, но я совершенно сбит с толку этим:

Это отображает раскрывающийся список без выбранных значений:

<%= Html.DropDownList("items", new MultiSelectList(Model.AvailableItems,
    "id", "name", Model.items), new { multiple = "multiple" })%>

Это отображает раскрывающийся список сзначения, которые я передаю (Model.items), выбраны правильно, как и ожидалось:

<%= Html.DropDownList("somethingelse", new MultiSelectList(Model.AvailableItems,
    "id", "name", Model.items), new { multiple = "multiple" })%>

Но проблема в том, что этот элемент теперь называется "someelse", когда я POST.Я знаю, что могу взломать это, но что происходит?

Ответы [ 6 ]

51 голосов
/ 18 сентября 2010

В вашем вопросе слишком мало контекста, но я постараюсь показать полный рабочий пример:

Модель:

public class Item
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class MyModel
{
    public IEnumerable<int> SelectedItemIds { get; set; }
    public IEnumerable<Item> AvailableItems { 
        get 
        {
            return new[] 
            {
                new Item { Id = 1, Name = "Item 1" },
                new Item { Id = 2, Name = "Item 2" },
                new Item { Id = 3, Name = "Item 3" },
            };
        } 
    }
}

Контроллер:

[HandleError]
public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new MyModel
        {
            SelectedItemIds = new[] { 2, 3 }
        };
        return View(model);
    }

    [HttpPost]
    public ActionResult Index(IEnumerable<int> selectedItemIds)
    {
        var model = new MyModel
        {
            // Important: Don't ever try to modify the selectedItemIds here
            // The Html helper will completely ignore it and use 
            // the POSTed values
            SelectedItemIds = selectedItemIds
        };
        return View(model);
    }
}

Просмотр:

<% using (Html.BeginForm()) { %>
    <%= Html.ListBoxFor(x => x.SelectedItemIds, 
        new MultiSelectList(Model.AvailableItems, "Id", "Name")) %>
    <input type="submit" value="GO" />
<% } %>

Обратите внимание, что Html.ListBoxFor более адаптирован, если вы хотите сгенерировать множественный выбор.Очевидно, что свойство AvailableItems должно быть получено из репозитория.

21 голосов
/ 21 сентября 2010

У вас проблема с использованием Model.Items в качестве параметра. Код

<%= Html.DropDownList("items", new MultiSelectList(Model.AvailableItems,
    "id", "name", Model.items), new { multiple = "multiple" })%>

на самом деле не работает так, как вы ожидаете. Это работает, потому что название выпадающего списка - "items". Это потому, что к вашему действию был добавлен параметр формы под названием «элементы». Этот параметр сохраняется в ViewState действия (не путайте с ViewData). Html.DropdownList () видит, что существует параметр ViewState с именем, совпадающим с именем раскрывающегося списка, и использует этот параметр ViewState для обработки выбранных значений. Он полностью игнорирует переданные вами Model.items.

Если кто-то может объяснить логику неспособности переопределить поведение по умолчанию, то я хотел бы услышать это.

Итак, это ваша первая проблема. Чтобы обойти это, все, что вам нужно сделать, это переименовать выпадающий список во что-то другое - точно так же, как вы это делали во втором примере. Теперь ваша вторая проблема вступает в игру: список выбранных элементов должен быть набором простых объектов (я думаю, что это действительно должен быть IEnumerable, но я не уверен на 100%).

Метод DropDownList () попытается сопоставить эти выбранные значения со значением в вашей коллекции AvailableItems. Если он не может этого сделать, он попытается сопоставить его с текстом.

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

<%= Html.DropDownList("somethingelse", new MultiSelectList(Model.AvailableItems,
    "id", "name", Model.items.Select(c=> c.name)), new { multiple = "multiple" })%>

Удачи

5 голосов
/ 26 ноября 2012

У меня была та же проблема, я использовал собственный метод расширения для генерации HTML, и проблема решена

    public static MvcHtmlString ListBoxMultiSelectFor<TModel, TProperty>(
        this HtmlHelper<TModel> helper,
        Expression<Func<TModel, TProperty>> expression,
        IEnumerable<SelectListItem> selectList,
        object htmlAttributes)
    {
        return ListBoxMultiSelectFor(helper, expression, selectList, new RouteValueDictionary(htmlAttributes));
    }

    public static MvcHtmlString ListBoxMultiSelectFor<TModel, TProperty>(
        this HtmlHelper<TModel> helper,
        Expression<Func<TModel, TProperty>> expression,
        IEnumerable<SelectListItem> selectList,
        IDictionary<string, object> htmlAttributes)
    {
        string name = ExpressionHelper.GetExpressionText(expression);

        TagBuilder selectTag = new TagBuilder("select");
        selectTag.MergeAttributes(htmlAttributes);
        selectTag.MergeAttribute("id", name, true);
        selectTag.MergeAttribute("name", name, true);
        foreach (SelectListItem item in selectList)
        {
            TagBuilder optionTag = new TagBuilder("option");
            optionTag.MergeAttribute("value", item.Value);
            if (item.Selected) optionTag.MergeAttribute("selected", "selected");
            optionTag.InnerHtml = item.Text;
            selectTag.InnerHtml += optionTag.ToString();
        }

        return  new MvcHtmlString(selectTag.ToString());
    }
4 голосов
/ 27 ноября 2014

На самом деле, если вы посмотрите на исходный код MVC, это поведение запечено в DropDownListFor по умолчанию (ищите allowMultiple: false). Решение состоит в том, чтобы вместо этого использовать ListBoxFor (вы также увидите, что в исходном коде MVC, allowMultiple: true), что имеет большой смысл с точки зрения HTML, оба варианта отображаются в

<select ...>
   <option ...>
   <option ...>
   ...
</select>

Вам не нужно использовать разные свойства в модели, как было предложено в ответах выше этого, я получил это, просто переключившись на ListBoxFor (CSS берет его оттуда):

@Html.ListBoxFor(model => model.SelectedCategories, 
   new MultiSelectList(Model.Categories, Model.SelectedCategories),
   new { multiple = "multiple" })

Работает как шарм, даже с POST и повторным отображением представления об ошибке.

1 голос
/ 02 апреля 2018

У меня была похожая проблема при использовании ListBoxFor и MultiSelectList, назначенных в качестве свойства ViewBag.@ jero's answer помог мне выяснить, что если между полем ViewBag и полем модели возникает конфликт имен, то выбранные значения отображаются некорректно.

Если я сделал следующее,элементы не отображаются как выбранные.

//Controller
ViewBag.SelectionIds = new MultiSelectView(possibleValues, "Value", "Name", selectedValues);

//View
@Html.ListBoxFor(model => model.SelectionIds, (MultiSelectList)ViewBag.SelectionIds, new { @class = "form-control" })

Если я изменил его на следующее, то все было в порядке.

//Controller
//Changed ViewBag.SelectionIds to ViewBag.SelectionIdList
ViewBag.SelectionIdList = new MultiSelectView(possibleValues, "Value", "Name", selectedValues);

//View
@Html.ListBoxFor(model => model.SelectionIds, (MultiSelectList)ViewBag.SelectionIdList, new { @class = "form-control" })
0 голосов
/ 30 марта 2016

Вы можете перейти к значению «items» с помощью этого

<HttpPost()> _
    Function Edit(ByVal crm_cliente As crm_cliente, ByVal form As FormCollection) As ActionResult
        If ModelState.IsValid Then
            Dim items As String
            crm_cliente.usuario_modifico = "ejmorales"
            crm_cliente.fecha_modifico = Date.Now
            items = form("items")

, которая выдаст вам выбранные элементы в виде строки, разделенной запятыми (,)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...