web-dev-qa-db-fra.com

DropDownList définissant l'élément sélectionné dans asp.net MVC

J'ai remarqué ce qui me semble être un bug dans asp.net MVC ou simplement je fais quelque chose de mal. J'utilise actuellement 1.0, donc c'est peut-être quelque chose qui sera abordé dans la version 2.0. Mais de toute façon, c'est parti.

Lorsque mon modèle de vue possède une propriété qui porte le même nom que l'ID déclaré pour une liste déroulante, l'élément sélectionné est ignoré et le code HTML rendu n'a rien de sélectionné. Je ne sais pas si j'ai fait quelque chose de mal, mais changer le nom de l'identifiant résout le problème. J'ai simplifié l'exemple, j'espère qu'il est clair, sinon faites le moi savoir.

Voici ma vue où l'ID déclaré est le même nom que ma liste dans le modèle:

<table border="0" cellpadding="0" cellspacing="0">
   <tr>
      <td>
         <%= Html.DropDownList("IsMultipleServicers", Model.IsMultipleServicers) %>
      </td>
   </tr>
</table>

Et le Html rend

<table border="0" cellpadding="0" cellspacing="0">
      <tr>
         <td>
             <select id="IsMultipleServicers" name="IsMultipleServicers">
                <option value="false">No</option>
                <option value="true">Yes</option>
             </select>
         </td>
      </tr>
</table>

Maintenant, faisons un petit changement. Je changerai l'identifiant déclaré pour qu'il soit différent.

Voici ma vue:

<table border="0" cellpadding="0" cellspacing="0">
    <tr>
       <td>
          <%= Html.DropDownList("MultipleServicers", Model.IsMultipleServicers) %>
       </td>
    </tr>
</table>

Et maintenant le html rendu:

<table border="0" cellpadding="0" cellspacing="0">
   <tr>
      <td>
         <select id="IsMultipleServicers" name="IsMultipleServicers">
            <option value="false">No</option>
            <option selected="selected" value="true">Yes</option>
         </select>
      </td>
   </tr>
</table>

Notez que maintenant j'obtiens une option sélectionnée qui serait le deuxième élément de la liste.

Voici mon ViewModel juste pour tout lier:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MVCProject.Models.ViewModels.Service
{
    public class ServiceViewModel : ViewModel
    {
         public List<SelectListItem> IsMultipleServicers { get; set; }
    }
}

Voici mon action:

[AcceptVerbs(HttpVerbs.Get)]
public virtual ActionResult Service()
{
   return View(new ServiceViewModel()
   {
      IsMultipleServicers = BuildBooleanSelectList(true)
   };
}

 private List<SelectListItem> BuildBooleanSelectList(bool isTrue)
 {
    List<SelectListItem> list = new List<SelectListItem>();

    if (isTrue)
    {
       list.Add(new SelectListItem() { Selected = false, Text = "No", Value = "false" });
       list.Add(new SelectListItem() { Selected = true, Text = "Yes", Value = "true" });
    }
    else
    {
       list.Add(new SelectListItem() { Selected = true, Text = "No", Value = "false" });
       list.Add(new SelectListItem() { Selected = false, Text = "Yes", Value = "true" });
    }
 return list;
  }
26
Gabe

Je pense que le problème est une confusion concernant les surcharges DropDownList:

  1. Html.DropDownList(string name) recherche une propriété de modèle de vue de name et tapez IEnumerable<SelectListItem>. Il utilisera l'élément sélectionné (SelectListItem.Selected == true) Dans la liste, sauf s'il existe une valeur de publication de formulaire du même nom.

  2. Html.DropDownList(string name, IEnumerable<SelectListItem> selectList) utilise les éléments de selectList, mais pas leurs valeurs sélectionnées. La sélection est trouvée en résolvant name dans le modèle de vue (ou en postant les données) et en le comparant au SelectListItem.Value. Même si la valeur est introuvable (ou est nulle), elle n'utilisera toujours pas la valeur sélectionnée dans la liste de SelectListItems.

Votre code utilise la deuxième surcharge, mais spécifie une propriété "value" qui n'existe pas ("MultipleServicers").

Pour résoudre votre problème, utilisez soit la première surcharge:

<%= Html.DropDownList("IsMultipleServicers") %>

Ou, ajoutez une propriété string MultipleServicers À votre modèle de vue et remplissez-la dans votre contrôleur. Je recommanderais cette solution car elle contourne plusieurs problèmes d'affichage initial, de post-affichage et de mappage des données de post à un modèle de vue/post:

public class ServiceViewModel : ViewModel 
{ 
     public string MultipleServicers { get; set; } 
     public List<SelectListItem> IsMultipleServicers { get; set; } 
}

Alors pour votre HTML:

<%= Html.DropDownList(Model.MultipleServicers, Model.IsMultipleServicers) %>

Cette technique correspond également à MVC2:

<%= Html.DropDownListFor(x => x.MultipleServicers, Model.IsMultipleServicers) %>
44
Richard Szalay

J'ai rencontré ce même problème en utilisant la surcharge Html.DropDownList (nom de chaîne, IEnumerable selectList). Il semble que mon modèle possède une propriété du même nom que le nom de la liste déroulante. Cela étant le cas, MVC a préféré la valeur de propriété de mon modèle à la propriété sélectionnée de chaque entrée dans IEnumerable.

La solution était d'utiliser un nom pour la liste déroulante qui ne correspond pas à un nom de propriété. Une autre solution serait d'écrire ma propre méthode d'extension qui ignore le modèle et l'état d'affichage et, à la place, respecte toujours la propriété sélectionnée.

9
Tim

L'assistant DropDownList extrait la valeur par défaut du modèle. Dans le premier cas, la valeur dans le modèle correspondant au nom est une SelectList - cela ne correspond à aucun des éléments de la liste, c'est la liste, donc aucune valeur n'est choisie. Dans le deuxième exemple, votre modèle n'inclut pas de propriété portant ce nom, la valeur du modèle ne peut donc pas être utilisée et il correspond par défaut à l'état indiqué dans la SelectList elle-même. En règle générale, j'ai une propriété sur le modèle pour la valeur sélectionnée - cela devient la valeur par défaut - et une autre propriété représentant les valeurs potentielles de la liste.

2
tvanfosson