En travaillant sur ma première application Web ASP.Net MVC2 récemment, je suis tombé sur quelques problèmes lorsque je devais sélectionner plusieurs valeurs dans une zone de liste. J'ai travaillé sur cela avec un peu de jQuery, mais je suis allé de l'avant et j'ai mis en place un code très simple à démontrer. J'utilise EF pour le modèle, avec deux entités - Clients et HelpDeskCalls:
Manette:
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);
}
Vue:
<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>
Pour cet exemple, je sélectionne simplement HelpDeskCall.ID qui sont pairs. J'essaie deux syntaxes différentes pour ListBoxFor: l'une utilise un IEnumerable de valeurs pour les sélections, l'autre utilisant un IEnumerable de SelectListItems. Par défaut, lorsque j'exécute ce code, aucune sélection n'est effectuée dans ListBoxFor, mais le ListBox non typé est sélectionné correctement.
J'ai lu ce post sur ASP.Net et ce fil sur SO, mais pas de joie. En fait, si j'ajoute le remplacement ToString () à ma classe HelpDeskCall (comme suggéré dans le fil ASP.net), toutes les valeurs sont sélectionnées, ce qui n'est pas correct non plus.
Si quelqu'un pouvait nous expliquer comment cela fonctionnerait (et ce que je manque ou ce que je fais mal), ce néophyte serait alors très reconnaissant.
Voici un exemple illustrant la version fortement typée:
Modèle:
public class MyViewModel
{
public int[] SelectedItemIds { get; set; }
public MultiSelectList Items { get; set; }
}
Manette:
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);
}
}
Vue:
<%: Html.ListBoxFor(x => x.SelectedItemIds, Model.Items) %>
Je ne sais pas si ce comportement a changé dans le RTM de MVC3 que j'utilise, mais il semble que la sélection et la liaison fonctionnent désormais de manière opérationnelle. Le seul problème est que le modèle doit contenir une propriété avec les ID, comme ceci:
public class MyViewModel {
public int[] ItemIDs { get; set; }
}
Ensuite, les éléments suivants dans la vue fonctionneraient correctement, présélectionnant les valeurs correctes et liant correctement lors de la publication:
@Html.ListBoxFor(model => model.ItemIDs, (IEnumerable<SelectListItem>)(new[] {
new SelectListItem() { Value = "1", Text = "1" },
new SelectListItem() { Value = "2", Text = "2" }
}))
J'ai trouvé une meilleure solution de contournement. Manière habituelle de présélectionner la liste de sélection:
@Html.ListBoxFor(
model => model.Roles,
new MultiSelectList(db.Roles, "Id", "Name")
)
@Html.ValidationMessageFor(model => model.Roles)
Ne fonctionne pas, jamais aucune option n'est sélectionnée jusqu'à ce que:
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);
}
Les rôles sélectionnés doivent être stockés dans ViewData, pour éviter un bogue méchant.
Une autre option consiste à tirer parti de nameof.
Html.ListBox(nameof(MainProjectViewModel.Projects), Model.Projects)