Sfide con la selezione dei valori in ListBoxFor

Recentemente, lavorando alla mia prima app web ASP.Net MVC2, ho riscontrato alcuni problemi quando avevo bisogno di selezionare più valori in una casella di riepilogo. Ho lavorato intorno ad esso con alcuni jQuery, ma sono andato avanti e ho messo insieme un codice molto semplice da dimostrare. Sto utilizzando EF per il modello, con due quadro: Clienti e HelpDeskCalls:

controller:

public ActionResult Edit(int id) { Customer currCustomer = ctx.Customers.Include("HelpDeskCalls").Where(c => c.ID == id).FirstOrDefault(); List currCustCalls = (ctx.HelpDeskCalls.Where(h => h.CustomerID == id)).ToList(); List currSelectItems = new List(); List selectedValues = new List(); 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) currSelectItems; ViewData["currSelected"] = (IEnumerable) selectedValues; return View("Edit", currCustomer); } 

Vista:

 
model.HelpDeskCalls, new MultiSelectList(Model.HelpDeskCalls, "ID", "CallTitle", (IEnumerable) ViewData["currSelected"]), new { size = "12" })%> model.HelpDeskCalls, ViewData["currCalls"] as IEnumerable, new { size = "12"}) %> model.HelpDeskCalls) %>

Per questo esempio, sto selezionando HelpDeskCall.IDs che sono pari. Sto provando due diverse syntax per ListBoxFor: One utilizza un IEnumerable di valori per le selezioni, uno utilizza un object IEnumerable di SelectListItems. Per impostazione predefinita, quando eseguo questo codice, non vengono apportate selezioni a ListBoxFor, ma il ListBox non fortemente digitato seleziona correttamente.

Ho letto questo post su ASP.Net e questo thread su SO, ma nessuna gioia. Infatti, se aggiungo l’override di ToString () alla mia class HelpDeskCall (come suggerito nel thread ASP.net) tutti i valori sono selezionati, il che non è corretto neanche.

Se qualcuno potesse far luce su come dovrebbe funzionare (e cosa mi manca o cosa non va), questo neofita sarebbe molto grato.

Ecco un esempio che illustra la versione fortemente tipizzata:

Modello:

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

controller:

 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); } } 

Vista:

 < %: Html.ListBoxFor(x => x.SelectedItemIds, Model.Items) %> 

Non so se questo comportamento è cambiato nell’RTM di MVC3 che sto usando, ma sembra che la selezione e l’associazione ora funzionino fuori dalla scatola. L’unico problema è che il modello dovrebbe contenere una proprietà con gli ID, in questo modo:

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

Quindi la seguente vista funzionerebbe bene, sia preselezionando i valori corretti che vincolando correttamente durante il post:

 @Html.ListBoxFor(model => model.ItemIDs, (IEnumerable)(new[] { new SelectListItem() { Value = "1", Text = "1" }, new SelectListItem() { Value = "2", Text = "2" } })) 

Ho trovato una soluzione migliore. Modo usuale per preselezionare l’elenco selezionato:

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

Non funziona .., mai nessuna opzione è selezionata, fino a quando:

 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); } 

I ruoli selezionati devono essere memorizzati in ViewData, per aggirare un bug sgradevole.