Question

Je suis nouveau sur MVC, mais j'ai parcouru tout cela, lu toute la documentation, toutes les questions et tous les articles de blog que je peux trouver, et tout ce que je fais, c'est m'enrouler complètement autour de l'essieu.

J'essaie de créer une action et une vue "créer".Ma saisie de données est relativement simple et courante :J'ai une liste déroulante et une zone de texte.Dans mon cas, je crée un canal de contact utilisateur, et la liste déroulante choisit entre e-mail et SMS, et la zone de texte saisit ensuite les informations de contact pertinentes, soit une adresse e-mail bien formée, soit un numéro de téléphone portable.

Voici une (forme légèrement simplifiée) de ma page d'affichage :

 <tr>
     <td><%= Html.DropDownList("ChannelDescription", Model.ChannelDescription, "Select a Channel", new { id = "ChannelDDL", onchange="ChannelDDLChanged()" })%>
         <br />
         <%= Html.ValidationMessage("ChannelDescription", "Please Select a Channel") %>
      </td>
      <td>
           <%= Html.TextBox("SubscriberNotificationAddr") %> <br />
           <%= Html.ValidationMessage("SubscriberNotificationAddr", "Please enter a contact address or number") %>
       </td>
  </tr>

J'utilise un modèle ViewData fortement typé, plutôt que d'utiliser ViewDataDictionary.L'élément ChannelDescription est une SelectList, qui est initialisée avec la liste de choix et aucune sélection.

L'affichage initial du formulaire, la saisie des données dans le formulaire et l'extraction des données du formulaire par le responsable du traitement se déroulent correctement.

Mon problème est que si les données contiennent une erreur, telle qu'une adresse e-mail ou un numéro de téléphone portable mal formé, et que je dois revenir à la vue, je n'ai pas réussi à réafficher la sélection de la liste déroulante.L'élément ChannelDescription est recréé dans le contrôleur avec le choix de l'utilisateur comme élément sélectionné.J'ai défini des points d'arrêt sur cette ligne de la vue et vérifié que l'élément sélectionné de la liste d'éléments a la propriété Selected définie sur true, mais il affiche toujours la valeur par défaut "Sélectionner un canal".

Cela semble être une situation très courante et ne devrait pas être si difficile.Qu'est-ce que je fais mal?

Pour information, c'est avec MVC 1.0 (Release), Windows 7 et VS 2008, fonctionnant sous Firefox 3.5.2.

Était-ce utile?

La solution 2

J'ai eu quelques discussions avec Brad Wilson, de l'équipe MVC, et il m'a expliqué que je ne comprenais pas comment utiliser la méthode d'assistance DropDownList (un malentendu qui pourrait être assez courant, d'après ce que j'ai lu ).

En gros, donnez-lui la liste de sélection dans le paramètre nommé du ViewModel et laissez-la construire la liste déroulante avec les éléments appropriés sélectionnés, OU attribuez-lui la liste de sélection en tant que paramètre séparé et laissez le paramètre nommé de la ViewModel être juste les chaînes de valeur pour le ou les éléments sélectionnés. Si vous lui donnez un paramètre SelectList, il s'attend à ce que la valeur nommée soit une chaîne ou une liste de chaînes, PAS une liste SelectList.

Ainsi, votre ViewModel finit par avoir deux éléments pour un élément conceptuel dans la vue (la liste déroulante). Ainsi, vous pourriez avoir un modèle qui a

string SelectedValue {get; set;}
SelectList DropDownElements { get; set;}

Ensuite, vous pouvez pré-renseigner DropDownElements avec les choix, mais dans la liaison de votre vue Modèle, il vous suffit de traiter l'élément SelectedValue. Cela semble bien fonctionner pour moi quand je le fais de cette façon.

Autres conseils

Après avoir consulté la réponse ci-dessus, j'ai voulu la vérifier, car tous les exemples que j'avais vus utilisaient effectivement ViewDataDictionary, plutôt qu'un ViewDataModel fortement typé.

J'ai donc fait quelques expériences.J'ai construit une vue très simple qui utilisait un simple ViewDataDictionary et transmettait les valeurs par clés nommées.Il a très bien conservé l'élément sélectionné.Ensuite, j'ai coupé et collé cette vue (et ce contrôleur) dans une autre, en modifiant uniquement ce qui était nécessaire pour passer à un modèle ViewData fortement typé.Et voilà, l’élément sélectionné a également été conservé.

Alors, quelle était la différence entre mon simple test et ma candidature ?Dans mon test, j'avais utilisé simplement "Html.DropDownList("name", "optionLabel")".Cependant, dans mon application, j'avais besoin d'ajouter des attributs HTML, et les seules surcharges disponibles incluant HtmlAttributes incluent également la liste de sélection.

Il s'avère que la surcharge DropDownList avec un paramètre de liste de sélection est cassée !En regardant le code source MVC téléchargé, lorsque DropDownList est appelé avec juste un nom, ou un nom et un optionLabel, il finit par récupérer la liste de sélection cible à partir de ViewData, puis invoquer la méthode privée SelectInternal par l'appel suivant :

    return SelectInternal(htmlHelper, optionLabel, name, selectList, true /* usedViewData */, false /* allowMultiple */, (IDictionary<string, object>)null /* htmlAttributes */);

Cependant, s'il est appelé avec un paramètre selectList, il se termine par ce qui suit :

   return SelectInternal(htmlHelper, optionLabel, name, selectList, false /* usedViewData */, false /* allowMultiple */, htmlAttributes);

La différence est que dans le premier (qui fonctionnera correctement) le paramètre "usedViewData" est vrai, tandis que dans le second, il est faux.Ce qui est en fait correct, mais expose un défaut interne dans la routine SelectInternal.

Si usedViewData est faux, il obtient une variable objet « defaultValue » du modèle ViewData.Cependant, defaultValue est utilisé comme s'il s'agissait d'une chaîne ou d'un tableau de chaînes, alors qu'en fait ce qui est renvoyé par ViewData est une SelectList.(IEnumerable<SelectListItem>).

Si usedViewData est vrai, alors defaultValue sera soit null, soit une chaîne.

Ensuite, si defaultValue n'est pas nul, il finit par entrer dans un bloc de code qui contient ceci :

        foreach (SelectListItem item in selectList) {
            item.Selected = (item.Value != null) ? selectedValues.Contains(item.Value) : selectedValues.Contains(item.Text);
            newSelectList.Add(item);

selectList est la selectList d'origine qui a été transmise, donc l'élément est un SelectListItem (string Text, string Value et bool Selected).Mais selectedValues ​​a été dérivé de defaultValue et devient une liste de SelectLists, pas une liste de chaînes.Ainsi, pour chacun des éléments, il définit l'indicateur Selected selon que la liste selectedValues ​​"Contient" l'élément.Value.Eh bien, une liste de SelectLists ne "contiendra" jamais une chaîne, donc l'élément item.Selected n'est jamais défini.(Correction:en fait, après plus de traçage avec le débogueur, j'ai trouvé que selectedValues ​​est dérivé de defaultValue par un appel "ToString()".Il s'agit donc en fait d'une liste de chaînes, mais au lieu de contenir les valeurs souhaitées, elle contient "System.Web.Mvc.SelectList" - le résultat de l'application de "ToString()" à un objet complexe comme une SelectList.Le résultat est toujours le même : nous n'allons pas trouver la valeur que nous recherchons dans cette liste.)

Il remplace ensuite la "newSelectList" nouvellement construite par la "selectList" d'origine et procède à la construction du code HTML à partir de celle-ci.

Comme cagdas (je m'excuse d'avoir massacré votre nom, mais je ne sais pas comment créer ces caractères sur mon clavier américain) l'a dit ci-dessus, je pense que je vais devoir créer ma propre méthode à utiliser à la place du DropDownList HtmlHelper.Je suppose que puisque cette version 1 et Release2 sont en version bêta 2, nous ne pouvons pas vraiment nous attendre à des corrections de bugs à moins de le faire nous-mêmes, n'est-ce pas ?

BTW, si vous m'avez suivi jusqu'ici, ce code se trouve dans src\SystemWebMvc\Mvc\Html\SelectExtensions.cs, vers les lignes 116-136.

Oui, j'ai aussi eu tant de problèmes à faire en sorte que DropDownList respecte l'élément sélectionné que je lui ai donné.

Veuillez vérifier mon répondez à cette question . Autant que je m'en souvienne, c'était la seule façon pour moi de le faire fonctionner. En passant la liste via ViewData.

Pour info, j'ai arrêté d'utiliser cette méthode HtmlHelper. Je sors tout simplement les balises <select> et <option> moi-même avec une boucle et définit la propriété selected de la balise option en la vérifiant moi-même.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top