Почему ListBox не выбирает элементы, а ListBox? - PullRequest
29 голосов
/ 22 февраля 2010

У меня есть следующий код на мой взгляд:

<%= Html.ListBoxFor(c => c.Project.Categories,
        new MultiSelectList(Model.Categories, "Id", "Name", new List<int> { 1, 2 }))%>

<%= Html.ListBox("MultiSelectList", 
        new MultiSelectList(Model.Categories, "Id", "Name", new List<int> { 1, 2 }))%>

Единственное отличие состоит в том, что первый помощник имеет строгую типизацию (ListBoxFor), а не отображает выбранные элементы (1,2), даже если элементы отображаются в списке и т. Д. Более простой ListBox работает как положено.

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

Для справки, моя модель:

public class ProjectEditModel
{
    public Project Project { get; set; }
    public IEnumerable<Project> Projects { get; set; }
    public IEnumerable<Client> Clients { get; set; }
    public IEnumerable<Category> Categories { get; set; }
    public IEnumerable<Tag> Tags { get; set; }
    public ProjectSlide SelectedSlide { get; set; }
}

Обновление

Я просто изменил имя ListBox на Project.Categories (соответствует моей модели), и теперь он не может выбрать элемент.

<%= Html.ListBox("Project.Categories",
        new MultiSelectList(Model.Categories, "Id", "Name", new List<int> { 1, 2 }))%>

Я явно не понимаю магию, которая здесь происходит.

Обновление 2

Хорошо, это чисто именование, например, это работает ...

<%= Html.ListBox("Project_Tags",
new MultiSelectList(Model.Tags, "Id", "Name", Model.Project.Tags.Select(t => t.Id)))%>

... потому что имя поля Project_Tags, а не Project.Tags, на самом деле, будет работать что угодно, кроме тегов или Project.Tags. Я не понимаю, почему это может вызвать проблемы (кроме того, что это соответствует имени сущности), и я не достаточно хорош в этом, чтобы копаться и узнавать.

Ответы [ 7 ]

25 голосов
/ 08 декабря 2011

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

Вы не можете присвоить имя PopBet ViewBag или ViewData, содержащему SelectList или MultiSelectList, тому же имени, что и ваша модель свойств, содержащая выбранные элементы. По крайней мере, если вы используете помощник ListBoxFor или DropDownListFor.

Вот пример:

    public class Person
    {
          public List<int> Cars { get; set; }
    }

    [HttpGet]
    public ActionResult Create()
    {
          //wont work
          ViewBag.Cars = new SelectList(carsList, "CarId", "Name"); 

          //will work due to different name than the property.
          ViewBag.CarsList = new SelectList(carsList, "CarId", "Name"); 

          return View();
    }

    //View
    @Html.ListBoxFor(model => model.Cars, ViewBag.CarsList as SelectList)

Я уверен, что есть много других способов сделать это, но это решило мою проблему, надеюсь, это кому-нибудь поможет!

3 голосов
/ 04 октября 2011

Правильный ответ: он не очень хорошо работает. Как таковой, я прочитал код MVC. Что вам нужно сделать, это реализовать IConvertible, а также создать TypeConverter.

Итак, в моем случае у меня был класс Country, так что люди могли выбирать из списка стран. Нет радости в выборе. Я ожидал, что объект равняется сравнению selectedItems с listitems, но нет, это не так. Несмотря на то, что MultiListItem работает и правильно получает выбранные элементы, в тот момент, когда он привязан к вашей модели, все это основано на проверке соответствия строки вашего экземпляра объекта строке "value" (или имени, если оно отсутствует) в списке предметов в SelectItemList.

Итак, реализуйте IConvertible, верните строковое значение из ToString, которое будет соответствовать значению в SelectItemList. например, в моем случае CountryCode был сериализован в свойство SelectItem Value, поэтому в ToString IConvertible я вернул CountryCode. Теперь все выбирается правильно.

Я укажу, что TypeConverter используется при входе. На этот раз оно обратное. Это Countrycode возвращается, и "EN" необходимо преобразовать в экземпляр класса Country. Вот тут и пришло TypeConverter. Также пришло время понять, насколько сложно использовать этот подход.

p.s, поэтому в вашем Category классе вам нужно реализовать IConvertible. Если это из структуры сущностей, как моя компания, то вам нужно будет использовать частичный класс для реализации IConvertible и реализации ToString и украсить его TypeConverter, который вы тоже написали.

3 голосов
/ 30 июля 2010

Я также застрял с этой же проблемой и столкнулся с той же проблемой с ListBox и ListBoxFor.

Независимо от того, что я делаю, я не могу получить выбор в ListBoxFor. Если я перехожу на ListBox и называю его ДРУГОЙ, чем имя свойства данных, к которым я привязываю, происходит выбор.

Но тогда, поскольку я не использую ListBoxFor, а данные находятся, например, внутри класса модели (Model.Departments), я не получаю привязку модели на обратном пути к моему контроллеру, и, следовательно, свойство имеет значение null.

РЕДАКТИРОВАТЬ Я нашел решение, опубликованное кем-то еще здесь; Проблемы с выбором значений в ListBoxFor

2 голосов
/ 18 июля 2011

Также вы можете попытаться очистить ModelState для c.Project.Categories в контроллере:

[HttpPost]
public ActionResult Index(ModelType model)
{
    ModelState.Remove("Project.Categories");
    return View("Index", model);
}

И используйте следующую конструкцию:

<%= Html.ListBoxFor(c => c.Project.Categories,
        new MultiSelectList(Model.Categories, "Id", "Name"))%>

Где c.Project.Categories: IEnumerable<int>.

Извините за мой английский. Удачи!

1 голос
/ 19 августа 2011

Html.ListboxFor и Html.Listbox отлично работают, когда вы НЕ привязываете список к его источнику данных. Я предполагаю, что предполагаемое использование это:

// Model
public class ListBoxEditModel
{
    public IEnumerable<Category> Categories { get; set; }
    public IEnumerable<Category> SelectedCategories { get; set; }
}    

По виду:

@Html.ListBoxFor(m => m.SelectedCategories,
                 new MultiSelectList(Model.Categories, "Id", "Name"))
// or, equivalently
@Html.ListBox("SelectedCategories" ,
                 new MultiSelectList(Model.Categories, "Id", "Name"))

Обратите внимание, что в этом случае вам не нужно явно указывать, какие значения выбраны в MultiSelectList - модель, к которой вы привязываетесь, имеет приоритет, даже если вы делаете!

1 голос
/ 12 мая 2010

Попробуйте это

<%= Html.ListBoxFor(c => c.Project.Categories,
    new MultiSelectList(
        Model.Categories
        ,"Id"
        ,"Name"
        ,Model.Project.Tags.Select(
        x => new SelectListItem()
            {
            Selected = true,
            Text = x.TEXT,
            Value = x.ID.ToString()
            }).ToList())

       )
)%>
1 голос
/ 24 февраля 2010

Хотя это не ответ на ваш главный вопрос, стоит отметить, что когда MVC генерирует имена, он превращает что-то вроде Project.Tags в Project_Tags, заменяя точки подчеркиванием.

Причина, по которой это происходит, заключается в том, что точка в идентификаторе элемента будет выглядеть как элемент с именем Project с классом Tags to CSS. Очевидно, что это плохо, поэтому перевод подчеркивает, чтобы поведение было предсказуемым.

В вашем первом примере,

<%= Html.ListBoxFor(c => c.Project.Categories,
    new MultiSelectList(Model.Categories, "Id", "Name", new List<int> { 1, 2 }))%>

список пытается привязать к Model.Project.Categories для вашей строго типизированной Модели, которая была предоставлена ​​странице (используя лямбда-нотацию). Я не уверен, что делает второй параметр в ListBoxFor.

Какая модель передается на страницу?

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