2016-11-21 1 views
6

J'ai lu de nombreux articles sur l'utilisation de MultiSelectList et je n'ai pas encore compris ce qui ne va pas avec DropDownListFor. J'ai un ListBoxFor avec le même View, ViewModel et les données qui fonctionnent bien. Je veux utiliser DropDownListFor en raison de son paramètre optionLabel que ListBoxFor n'a pas. Lorsque la vue est chargée pour la première fois, DropDownListFor et ListBoxFor affichent les éléments multiples sélectionnés.Pourquoi DropDownListFor perd-il la sélection multiple après Submit mais pas ListBoxFor?

Initial View

Lorsque le bouton Soumettre est cliqué, la collection d'éléments sélectionnés est réaffecté à l'action du contrôleur correct et la vue est actualisée avec le ListBoxFor montrant encore les éléments sélectionnés mais le DropDownListFor est montrant qu'un seul élément sélectionné .

Refreshed View L'action du contrôleur est en train de construire la MultiSelectList comme ceci:

vm.TasksFilterGroup.Assignees = new MultiSelectList(employees, "Id", "FullName", new string[] { "51b6f06a-e04d-4f98-88ef-cd0cfa8a2757", "51b6f06a-e04d-4f98-88ef-cd0cfa8a2769" }); 

Le code Voir ressemble à ceci:

<div class="form-group"> 
 
    <label>ListBoxFor</label> 
 
    @Html.ListBoxFor(m => m.TasksFilterGroup.SelectedAssignees, Model.TasksFilterGroup.Assignees, new { @class = "form-control", multiple = "multiple" }) 
 
</div> 
 
<div class="form-group"> 
 
    <label>DropDownListFor</label> 
 
    @Html.DropDownListFor(m => m.TasksFilterGroup.SelectedAssignees, Model.TasksFilterGroup.Assignees, new { @class = "form-control", multiple = "multiple" }) 
 
</div>

Pourquoi le DropDownListFor perd la sélection multiple après Déposer mais le ListBoxFor ne le fait pas?

Répondre

15

Comme les noms des méthodes impliquent, DropDownListFor() est pour la création d'un <select> (pour sélectionner l'option 1) et ListBoxFor() est pour la création d'un <select multiple> (pour sélectionner plusieurs options). Bien que les deux méthodes partagent beaucoup de code commun, elles produisent des résultats différents. L'ajout de l'attribut multiple="multiple" modifie l'affichage, mais ne change pas la fonctionnalité du code exécuté par ces méthodes.

Si vous inspectez le source code, vous remarquerez que toutes les surcharges de DropDownListFor() finalement appeler la méthode private static MvcHtmlString DropDownListHelper() et, de même ListBoxFor() appelle finalement la méthode private static MvcHtmlString ListBoxHelper().

Ces deux méthodes appellent la méthode private static MvcHtmlString SelectInternal(), mais la différence est que DropDownListHelper() passe allowMultiple = false tandis que le ListBoxHelper() passe allowMultiple = true.

Dans le procédé SelectInternal(), la ligne clé de code est

object defaultValue = (allowMultiple) ? htmlHelper.GetModelStateValue(fullName, typeof(string[])) : htmlHelper.GetModelStateValue(fullName, typeof(string)); 

La valeur de defaultValue est ensuite utilisé lors de la construction html pour les <option> éléments et est utilisée pour définir l'attribut selected (s).

Dans le cas de ListBoxFor(), la valeur defaultValue sera le tableau défini par votre propriété SelectedAssignees. Dans le cas de DropDownListFor(), il renvoie null car la valeur de votre propriété ne peut pas être convertie en string (c'est un tableau).

Parce que defaultValue est null, aucun des éléments <option> ont l'attribut selected défini et vous perdez modèle de liaison. En remarque, si vous deviez définir les valeurs SelectedAssignees dans la méthode GET avant de transmettre le modèle à la vue, vous verrez qu'aucun d'entre eux n'est sélectionné lors de l'utilisation de DropDownListFor() pour les mêmes raisons que celles décrites ci-dessus.

Notez également que le code pour générer le SelectList doit juste être

vm.TasksFilterGroup.Assignees = new SelectList(employees, "Id", "FullName" }); 

Il n'y a pas de point régler le 3ème paramètre lorsque vous utilisez soit les DropDownListFor() ou ListBoxFor() méthodes parce que sa valeur de la propriété de votre liant à (SelectedAssignees) qui détermine quelles options sont sélectionnées (le troisième paramètre est ignoré par les méthodes). Si vous voulez les options correspondant à ces valeurs Guid à sélectionner, puis dans la méthode GET, utilisez

vm.TasksFilterGroup.SelectedAssignees= new string[]{ "51b6f06a-e04d-4f98-88ef-cd0cfa8a2757", "51b6f06a-e04d-4f98-88ef-cd0cfa8a2769" }; 
+1

Cette réponse complète et bien informé est très apprécié. Je vous remercie. – RJBreneman

+0

C'est une réponse géniale et approfondie. Très perspicace. – CodingYoshi