Проблемы с выбором значений в ListBoxFor - PullRequest
45 голосов
/ 07 июля 2010

Недавно работая над моим первым веб-приложением ASP.Net MVC2, я столкнулся с некоторыми проблемами, когда мне нужно было выбрать несколько значений в списке. Я работал над этим с помощью некоторого jQuery, но продолжил и собрал очень простой код для демонстрации. Я использую EF для модели с двумя объектами - Customers и HelpDeskCalls:

Контроллер:

 public ActionResult Edit(int id)
    {
        Customer currCustomer = ctx.Customers.Include("HelpDeskCalls").Where(c => c.ID == id).FirstOrDefault();
        List<HelpDeskCall> currCustCalls = (ctx.HelpDeskCalls.Where(h => h.CustomerID == id)).ToList();
        List<SelectListItem> currSelectItems = new List<SelectListItem>();
        List<String> selectedValues = new List<string>();
        foreach (HelpDeskCall currCall in currCustCalls)
        {
            bool isSelected = (currCall.ID % 2 == 0) ? true : false;
            //Just select the IDs which are even numbers...
            currSelectItems.Add(new SelectListItem() { Selected = isSelected, Text = currCall.CallTitle, Value = currCall.ID.ToString() });
            //add the selected values into a separate list as well...
            if (isSelected)
            {
                selectedValues.Add(currCall.ID.ToString());
            }
        }
        ViewData["currCalls"] = (IEnumerable<SelectListItem>) currSelectItems;
        ViewData["currSelected"] = (IEnumerable<String>) selectedValues;
        return View("Edit", currCustomer);
    }

Вид:

<div class="editor-field">
    <%: Html.ListBoxFor(model => model.HelpDeskCalls, new MultiSelectList(Model.HelpDeskCalls, "ID", "CallTitle", (IEnumerable) ViewData["currSelected"]), new { size = "12" })%>       
    <%: Html.ListBoxFor(model => model.HelpDeskCalls, ViewData["currCalls"] as IEnumerable<SelectListItem>, new { size = "12"}) %>
    <%: Html.ListBox("Model.HelpDeskCalls", new MultiSelectList(Model.HelpDeskCalls, "ID", "CallTitle", (IEnumerable)ViewData["currSelected"]), new { size = "12"}) %>      
    <%: Html.ValidationMessageFor(model => model.HelpDeskCalls) %>
</div>

Для этого примера я просто выбираю HelpDeskCall.ID, которые являются четными. Я пытаюсь два разных синтаксиса для ListBoxFor: один использует IEnumerable значений для выбора, другой использует IEnumerable из SelectListItems. По умолчанию, когда я запускаю этот код, выбор ListBoxFor не выполняется, но ListBox не строго типизирован и выбирается правильно.

Я прочитал этот пост на ASP.Net и этот пост на SO, но не радость. Фактически, если я добавлю переопределение ToString () в мой класс HelpDeskCall (как предложено в потоке ASP.net), все значения будут выбраны, что тоже неправильно.

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

Ответы [ 4 ]

91 голосов
/ 07 июля 2010

Вот пример, иллюстрирующий строго типизированную версию:

Модель:

public class MyViewModel
{
    public int[] SelectedItemIds { get; set; }
    public MultiSelectList Items { get; set; }
}

Контроллер:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        // Preselect items with id 1 and 3
        var selectedItemIds = new[] { 1, 3 };

        var model = new MyViewModel
        {
            Items = new MultiSelectList(
                new[] 
                {
                    // TODO: Fetch from your repository
                    new { Id = 1, Name = "item 1" },
                    new { Id = 2, Name = "item 2" },
                    new { Id = 3, Name = "item 3" },
                }, 
                "Id", 
                "Name", 
                selectedItemIds
            )
        };

        return View(model);
    }
}

Вид:

<%: Html.ListBoxFor(x => x.SelectedItemIds, Model.Items) %>
8 голосов
/ 19 января 2011

Я не знаю, изменилось ли это поведение в RTM MVC3, который я использую, но кажется, что выделение и привязка теперь работают из коробки.Единственный улов заключается в том, что модель должна содержать свойство с идентификаторами, например:

public class MyViewModel {
    public int[] ItemIDs { get; set; }
}

Тогда в представлении будет хорошо работать следующее, предварительно выбрав правильные значения и правильно связавшись во время публикации:

@Html.ListBoxFor(model => model.ItemIDs, (IEnumerable<SelectListItem>)(new[] { 
                                new SelectListItem() { Value = "1", Text = "1" }, 
                                new SelectListItem() { Value = "2", Text = "2" } 
                             }))
2 голосов
/ 08 сентября 2010

Я нашел лучший обходной путь. Обычный способ предварительного выбора списка выбора:

@Html.ListBoxFor(
    model => model.Roles, 
    new MultiSelectList(db.Roles, "Id", "Name")
)
@Html.ValidationMessageFor(model => model.Roles)    

Не работает .., никогда не будет выбрана никакая опция, до:

public ActionResult Edit(int id)
{
    var user = db.Users.Find(id);
    // this is workaround for http://aspnet.codeplex.com/workitem/4932?ProjectName=aspnet
    ViewData["Roles"] = user.Roles.Select(r => r.Id);
    return View(user);
}

Выбранные роли должны храниться во ViewData, чтобы обойти неприятную ошибку.

0 голосов
/ 24 сентября 2018

Другой вариант - воспользоваться nameof, вы можете сделать что-то вроде этого;

Html.ListBox(nameof(MainProjectViewModel.Projects), Model.Projects)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...