Domanda

Sono nuovo in MVC, ma ho letto tutto, ho letto tutta la documentazione, tutte le domande e tutti i post del blog che riesco a trovare, e tutto quello che sto facendo è essere completamente avvolto attorno all'asse.

Sto cercando di creare un'azione e una vista "create".L'immissione dei dati è relativamente semplice e comune:Ho un elenco a discesa e una casella di testo.Nel mio caso, sto creando un canale di contatto utente e la casella a discesa sceglie tra e-mail e SMS, quindi la casella di testo inserisce le informazioni di contatto pertinenti, un indirizzo e-mail ben formato o un numero di cellulare.

Ecco una (forma leggermente semplificata) della mia pagina View:

 <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>

Sto utilizzando un modello ViewData fortemente tipizzato, anziché utilizzare ViewDataDictionary.L'elemento ChannelDescription è un SelectList, che viene inizializzato con l'elenco di scelte e nessuna selezione.

La visualizzazione iniziale del modulo, l'inserimento dei dati nel modulo e l'estrazione dei dati dal modulo da parte del responsabile del trattamento vanno bene.

Il mio problema è che se i dati contengono un errore, come un indirizzo e-mail o un numero di cellulare in formato errato, e devo tornare alla visualizzazione, non sono riuscito a visualizzare nuovamente la selezione dell'elenco a discesa.L'elemento ChannelDescription viene ricreato nel controller con la scelta dell'utente come elemento selezionato.Ho impostato i punti di interruzione su quella riga della vista e ho verificato che l'elemento selezionato dell'elenco di elementi abbia la proprietà Selezionata impostata su true, ma viene comunque visualizzata l'impostazione predefinita "Seleziona un canale".

Sembra che sia una situazione molto comune e non dovrebbe essere così difficile.Che cosa sto facendo di sbagliato?

Per tua informazione, questo è con MVC 1.0 (versione), Windows 7 e VS 2008, in esecuzione su Firefox 3.5.2.

È stato utile?

Soluzione 2

Ho avuto delle discussioni con Brad Wilson, del team MVC, e mi ha spiegato che stavo fraintendendo come usare il metodo helper DropDownList (un equivoco che penso possa essere abbastanza comune, da quello che ho letto ).

Fondamentalmente, OGNI assegnagli il SelectList nel parametro denominato del ViewModel e lascia che costruisca l'elenco a discesa da quello con gli elementi appropriati selezionati, O dagli il SelectList come parametro separato e lascia che il parametro nominato del ViewModel essere solo le stringhe di valore per gli elementi selezionati. Se gli dai un parametro SelectList, si aspetta che il valore indicato sia una stringa o un elenco di stringhe, NON un SelectList.

Quindi, ora ViewModel finisce per avere due elementi per un elemento concettuale nella vista (l'elenco a discesa). Pertanto, potresti avere un modello che ha

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

Quindi è possibile precompilare DropDownElements con le scelte, ma nella rilegatura della vista del modello, è sufficiente gestire l'elemento SelectedValue. Sembra funzionare abbastanza bene per me quando lo faccio in questo modo.

Altri suggerimenti

Dopo aver visualizzato la risposta sopra, volevo verificarla, perché tutti gli esempi che avevo visto avevano effettivamente utilizzato ViewDataDictionary, piuttosto che un ViewDataModel fortemente tipizzato.

Quindi ho fatto alcuni esperimenti.Ho costruito una vista molto semplice che utilizzava un semplice ViewDataDictionary e passava i valori tramite chiavi denominate.Ha mantenuto correttamente l'elemento selezionato.Quindi ho tagliato e incollato quella vista (e controller) su un'altra, modificando solo ciò che era necessario per passare a un modello ViewData fortemente tipizzato.Ecco, anche l'elemento selezionato è rimasto persistente.

Quindi cos'altro c'era di diverso tra il mio semplice test e la mia domanda?Nel mio test ho utilizzato semplicemente "Html.DropDownList("name", "optionLabel")".Tuttavia, nella mia applicazione, avevo bisogno di aggiungere attributi HTML e gli unici sovraccarichi disponibili che includevano HtmlAttributes includono anche l'elenco di selezione.

Si scopre che il sovraccarico di DropDownList con un parametro dell'elenco di selezione è rotto!Osservando il codice sorgente MVC scaricato, quando DropDownList viene chiamato solo con un nome o con un nome e un'opzioneLabel, finisce per recuperare l'elenco di selezione di destinazione da ViewData e quindi invocare il metodo privato SelectInternal con la seguente chiamata:

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

Tuttavia, se viene chiamato con un parametro selectList, il risultato sarà quanto segue:

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

La differenza è che nel primo (che funzionerà correttamente) il parametro "usedViewData" è vero, mentre nel secondo è falso.Il che in realtà va bene, ma espone un difetto interno nella routine SelectInternal.

Se usedViewData è false, ottiene una variabile oggetto "defaultValue" dal modello ViewData.Tuttavia, defaultValue viene utilizzato come se fosse una stringa o un array di stringhe, quando in realtà ciò che viene restituito da ViewData è un SelectList.(IEnumerable<SelectListItem>).

Se usedViewData è true, defaultValue sarà null o una stringa.

Quindi se defaultValue non è nullo, finisce per entrare in un blocco di codice che contiene questo:

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

selectList è la selectList originale che è stata passata, quindi l'elemento è un SelectListItem (stringa Testo, stringa Valore e bool Selezionato).Ma selectValues ​​è stato derivato da defaultValue e diventa un elenco di SelectLists, non un elenco di stringhe.Pertanto, per ciascuno degli elementi, viene impostato il flag Selected in base al fatto che l'elenco dei valori selezionati "contenga" l'item.Value.Bene, un elenco di SelectLists non "conterrà mai" una stringa, quindi item.Selected non verrà mai impostato.(Correzione:in realtà, dopo ulteriori analisi con il debugger, ho scoperto cheselectedValues ​​deriva da defaultValue tramite una chiamata "ToString()".Quindi in realtà è un elenco di stringhe, ma invece di contenere i valori desiderati, contiene "System.Web.Mvc.SelectList", il risultato dell'applicazione di "ToString()" a un oggetto complesso come un SelectList.Il risultato è sempre lo stesso: non troveremo il valore che stiamo cercando in quell'elenco.)

Quindi sostituisce la "newSelectList" appena costruita con la "selectList" originale e procede a creare l'HTML da essa.

Come ha detto sopra cagdas (mi scuso per aver massacrato il tuo nome, ma non so come creare quei caratteri sulla mia tastiera americana), penso che dovrò creare il mio metodo da utilizzare al posto di DropDownList HtmlHelper.Immagino che dal momento che questa versione 1 e la versione 2 sono in Beta 2, non possiamo davvero aspettarci alcuna correzione di bug a meno che non lo facciamo noi stessi, giusto?

A proposito, se mi hai seguito fin qui, questo codice è in src\SystemWebMvc\Mvc\Html\SelectExtensions.cs, intorno alla riga 116-136

Sì, anch'io ho avuto così tanti problemi a far sì che DropDownList rispettasse l'elemento selezionato che gli ho dato.

Controlla my rispondi a questa domanda . Per quanto posso ricordare, era l'unico modo per farlo funzionare. Passando l'elenco tramite ViewData.

Cordiali saluti, ho smesso di usare quel metodo HtmlHelper. Ora sto semplicemente pubblicando i tag <select> e <option> me stesso con un ciclo e impostando la proprietà selected del tag option controllandolo da solo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top