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

ASP.NET MVC MultiSelectList с выбранными значениями, которые не выбраны должным образом

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

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

<%= 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" })%>

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

4b9b3361

Ответ 1

У вас есть проблема с Model.Items. Код

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

фактически не работает так, как вы ожидали. Он работает, потому что имя выпадающего списка - "элементы". Это потому, что в вашем действии появился параметр param, называемый "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" })%>

Удачи.

Ответ 2

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

Модель:

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 должно быть извлечено из репозитория.

Ответ 3

У меня была та же проблема, я использовал свой собственный метод расширения для генерации 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

На самом деле, если вы посмотрите на исходный код 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 и повторным отображением представления при ошибке.

Ответ 5

Вы можете перейти к значению "элементов" с помощью этого

<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")

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