Come posso far funzionare questa ASPLNET MVC SelectList?


126

Creo un elenco di selezione nel mio controller, da visualizzare nella vista.

Sto provando a crearlo al volo, una specie di cosa .. in questo modo ...

myViewData.PageOptionsDropDown = 
   new SelectList(new [] {"10", "15", "25", "50", "100", "1000"}, "15");

Si compila, ma l'output è male ...

<select id="PageOptionsDropDown" name="PageOptionsDropDown">
    <option>10</option>
    <option>15</option>
    <option>25</option>
    <option>50</option>
    <option>100</option>
    <option>1000</option>
</select>

Notare come nessun elemento è selezionato?

Come posso risolvere questo ??


1
Sei risposte ... una preferita ... nessun voto positivo: / Gli darò un +1
womp

Risposte:


128

Questo è come lo faccio

IList<Customer> customers = repository.GetAll<Customer>();
IEnumerable<SelectListItem> selectList = 
    from c in customers
    select new SelectListItem
    {
        Selected = (c.CustomerID == invoice.CustomerID),
        Text = c.Name,
        Value = c.CustomerID.ToString()
    };

Al secondo sguardo non sono sicuro di sapere cosa stai cercando ...


2
Grazie, questo mi ha aiutato a capire queste cose.
Cadoo,

6
Non risolve il problema relativo all'elemento selezionato ma è un ottimo modo per evitare le stringhe magiche per gli elenchi selezionati! Saluti
Alan Christensen,

11
Per risolvere il problema relativo all'elemento selezionato, aggiungi il seguente codice: SelectList sList = new SelectList(selectList, "Text", "Value", selected);dov'è selectedl'attuale cliente selezionato
jao

68

Uso un metodo di estensione:

uso

var departmentItems = departments.ToSelectList(d => d.Code + 
                                               " - " + d.Description,
                                               d => d.Id.ToString(),
                                               " - ");

var functionItems = customerFunctions.ToSelectList(f => f.Description, 
                                                   f => f.Id.ToString(), 
                                                   " - ");

con

public static class MCVExtentions
{
    public static List<SelectListItem> ToSelectList<T>(
        this IEnumerable<T> enumerable, 
        Func<T, string> text, 
        Func<T, string> value, 
        string defaultOption)
    {
        var items = enumerable.Select(f => new SelectListItem()
                                     {
                                         Text = text(f), 
                                         Value = value(f) 
                                     }).ToList();
        items.Insert(0, new SelectListItem()
                    {
                        Text = defaultOption, 
                        Value = "-1" 
                    });
        return items;
    }
}

simpatico. Ho aggiunto un Func selezionato, un'opzione defaultValue e un secondo sovraccarico senza impostazioni predefinite da specificare e questo funziona a meraviglia. A proposito, se vuoi rendere il tipo restituito IEnumerable <SelectListItem> puoi usare la sintassi return return per rendere questo aspetto davvero pulito
Chris Meek

48

Utilizzando il costruttore che accetta items, dataValueField, dataTextField, selectedValuecome parametri:

ViewData["myList"] = 
                new SelectList(new[] { "10", "15", "25", "50", "100", "1000" }
                .Select(x => new {value = x, text = x}), 
                "value", "text", "15");

Quindi a tuo avviso:

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

3
bello amico :) mi piace! stavo provando a fare questo .. ma non sono riuscito a ottenere la parte .Select (..) .. bello :) Lo proverò a casa, più tardi :)
Pure.Krome

1
Heya Cagdas. funziona alla grande, tranne che il campo selezionato non è selezionato. qualche idea? è un bug nelle cose MVC?
Pure.Krome,

2
L'elemento selezionato funziona quando si aggiunge l'elemento SelectList nell'oggetto ViewData (come in ViewData ["myList"] = new SelectList ..) e quindi si esegue il rendering con <% = Html.DropDownList ("myList")%>. Non sono riuscito a far funzionare l'elemento selezionato senza farlo in questo modo. Strano.
Çağdaş Tekin,

@Cagdas - ciao di nuovo amico .. non l'ho ancora capito :( Che cosa si tratta di un ViewData ??? Ho un ViewData fortemente tipizzato con proprietà propria .... ???
Pure.Krome

@ Pure.Krome - Ho preso quella proprietà dal tuo esempio nella domanda. Ora sto modificando l'esempio di codice. Si prega di vedere la mia modifica in pochi secondi.
Çağdaş Tekin,

19

Costruendo la risposta di Thomas Stock, ho creato questi ToSelectListmetodi sovraccarichi :

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

public static partial class Helpers
{
    public static IEnumerable<SelectListItem> ToSelectList<T>(this IEnumerable<T> enumerable, Func<T, object> value, bool selectAll = false)
    {
        return enumerable.ToSelectList(value, value, selectAll);
    }

    public static IEnumerable<SelectListItem> ToSelectList<T>(this IEnumerable<T> enumerable, Func<T, object> value, object selectedValue)
    {
        return enumerable.ToSelectList(value, value, new List<object>() { selectedValue });
    }

    public static IEnumerable<SelectListItem> ToSelectList<T>(this IEnumerable<T> enumerable, Func<T, object> value, IEnumerable<object> selectedValues)
    {
        return enumerable.ToSelectList(value, value, selectedValues);
    }

    public static IEnumerable<SelectListItem> ToSelectList<T>(this IEnumerable<T> enumerable, Func<T, object> value, Func<T, object> text, bool selectAll = false)
    {
        foreach (var f in enumerable.Where(x => x != null))
        {
            yield return new SelectListItem()
            {
                Value = value(f).ToString(),
                Text = text(f).ToString(),
                Selected = selectAll
            };
        }
    }

    public static IEnumerable<SelectListItem> ToSelectList<T>(this IEnumerable<T> enumerable, Func<T, object> value, Func<T, object> text, object selectedValue)
    {
        return enumerable.ToSelectList(value, text, new List<object>() { selectedValue });
    }

    public static IEnumerable<SelectListItem> ToSelectList<T>(this IEnumerable<T> enumerable, Func<T, object> value, Func<T, object> text, IEnumerable<object> selectedValues)
    {
        var sel = selectedValues != null
            ? selectedValues.Where(x => x != null).ToList().ConvertAll<string>(x => x.ToString())
            : new List<string>();

        foreach (var f in enumerable.Where(x => x != null))
        {
            yield return new SelectListItem()
            {
                Value = value(f).ToString(),
                Text = text(f).ToString(),
                Selected = sel.Contains(value(f).ToString())
            };
        }
    }
}

Nel controller, è possibile effettuare le seguenti operazioni:

var pageOptions = new[] { "10", "15", "25", "50", "100", "1000" };
ViewBag.PageOptions = pageOptions.ToSelectList(o => o, "15" /*selectedValue*/);

E infine nella tua vista, inserisci:

@Html.DropDownList("PageOptionsDropDown", ViewBag.PageOptions as IEnumerable<SelectListItem>, "(Select one)")

Si otterrà l'output desiderato - ovviamente, puoi lasciare l' "(Select one)"opzioneLabel sopra se non vuoi il primo elemento vuoto:

<select id="PageOptionsDropDown" name="PageOptionsDropDown">
<option value="">(Select one)</option>
<option value="10">10</option>
<option selected="selected" value="15">15</option>
<option value="25">25</option>
<option value="50">50</option>
<option value="100">100</option>
<option value="1000">1000</option>
</select>

Aggiornamento: un elenco di codici rivisto è disponibile qui con commenti XML.


13

Il problema è che SelectList funziona come previsto. Il bug è nel design. È possibile impostare la proprietà selezionata in SelectedItem, ma questo verrà completamente ignorato, se si attraversa l'elenco con GetEnumerator () (o se Mvc lo fa per te). Mvc creerà invece nuovi SelectListItems.

È necessario utilizzare il cector SelectList con SelectListItem [], Text-Name, Value-Name e SelectedValue. Essere consapevoli di passare come SelectedValue il VALUE di SelectListItem, che si desidera selezionare, non SelectListItem stesso! Esempio:

SelectList sl = new SelectList( new[]{
  new SelectListItem{ Text="one", Value="1"},
  new SelectListItem{ Text="two", Value="2"},
  new SelectListItem{ Text="three", Value="3"}
}, "Text", "Value", "2" );

(non testato questo, ma ho avuto lo stesso problema)

quindi la seconda opzione otterrà l'attributo selezionato = "selezionato". Sembra un buon vecchio DataSet ;-)


11

Questa è un'opzione:

myViewData.PageOptionsDropDown = new[] 
{
 new SelectListItem { Text = "10", Value = "10" },
 new SelectListItem { Text = "15", Value = "15", Selected = true }
 new SelectListItem { Text = "25", Value = "25" },
 new SelectListItem { Text = "50", Value = "50" },
 new SelectListItem { Text = "100", Value = "100" },
 new SelectListItem { Text = "1000", Value = "1000" },
}

nuovo SelectListItem {Selected = true, Text = "15", Value = "15"} per il valore selezionato.
Cadoo,

oops, sì, ho dimenticato di includere la proprietà 'Selected', grazie Cadoo =)
murki

10

Se questo è letteralmente tutto ciò che vuoi fare, devi semplicemente dichiarare l'array come stringa per risolvere il problema dell'elemento selezionato:

myViewData.PageOptionsDropDown = 
   new SelectList(new string[] {"10", "15", "25", "50", "100", "1000"}, "15");

7

È molto semplice far funzionare insieme SelectList e SelectedValue, anche se la tua proprietà non è un oggetto semplice come Int, String o Double.

Esempio:

Supponendo che il nostro oggetto Region sia qualcosa del genere:

public class Region {
     public Guid ID { get; set; }
     public Guid Name { get; set; }
}

E il tuo modello di visualizzazione è simile a:

public class ContactViewModel {
     public DateTime Date { get; set; }
     public Region Region { get; set; }
     public List<Region> Regions { get; set; }
}

Puoi avere il codice qui sotto:

@Html.DropDownListFor(x => x.Region, new SelectList(Model.Regions, "ID", "Name")) 

Solo se si sovrascrive il metodo ToString dell'oggetto Region in qualcosa del tipo:

public class Region {
     public Guid ID { get; set; }
     public Guid Name { get; set; }

     public override string ToString()
     {
         return ID.ToString();
     }
}

Questo ha garanzia al 100% di funzionare.

Ma credo davvero che il modo migliore per far funzionare SelectList al 100% in tutte le circostanze sia quello di utilizzare il metodo Equals per testare il valore della proprietà DropDownList o ListBox rispetto a ciascun elemento nella raccolta articoli.


5

Sembra che se si dispone di una vista fortemente tipizzata, è necessario modificare l'ID del menu a discesa in modo che NON sia il nome di una proprietà sulla classe ereditata. È quindi necessario inserire una logica nel metodo di modifica (POST) per estrarre il valore selezionato da FORMCollection e inserirlo nell'istanza prima di eseguire le modifiche.

Questo è certamente un po 'strano, ma l'ho provato e funziona.

Quindi, se la tua classe ha un campo chiamato CountryId, e stai visualizzando un elenco di nomi di paesi, fai in modo che il menu a discesa abbia un ID di CountryName anziché CountryId, quindi nel post puoi fare qualcosa con Collection ["CountryName"] .


1
Sì, ho avuto lo stesso problema. Semplicemente cambiando il nome ha funzionato. Grazie!
Davekaro,

4

Ho avuto lo stesso identico problema. La soluzione è semplice Basta modificare il parametro "name" passato all'helper DropDownList in qualcosa che non corrisponde a nessuna delle proprietà esistenti nel ViewModel. leggi di più qui: http://www.dotnetguy.co.uk/post/2009/06/25/net-mvc-selectlists-selected-value-does-not-get-set-in-the-view

Cito Dan Watson:

In MVC se la vista è fortemente digitata, l'opzione selezionata dell'elenco selezionato verrà ignorata e la proprietà dell'opzione selezionata impostata sul costruttore non raggiungerà mai la vista e verrà invece selezionata la prima opzione nel menu a discesa (perché è ancora un po 'un mistero) .

Saluti!


3

Tutte queste risposte sembrano grandi, ma sembra che il controller stia preparando i dati per una vista in un formato strutturato ben noto anziché lasciare che la vista esegua semplicemente un IEnumerable <> consegnato tramite il modello e crei un elenco di selezione standard, quindi consenti a DefaultModelBinder rispedire l'oggetto selezionato tramite un parametro di azione. Sì, no, perché no? Separazione delle preoccupazioni, sì? Sembra strano avere il controller per creare qualcosa di specifico per l'interfaccia utente e Visualizza.


3

Semplice:

string[] someName = new string[] {"10", "15", "25", "50", "100", "1000"};
myViewData.PageOptionsDropDown = new SelectList(someName, "15");

2

L'ho fatto funzionare così e non ho avuto problemi,

public class myViewDataObj
    {
        public SelectList PageOptionsDropDown { get; set; }
    }

public ActionResult About()
        {
            myViewDataObj myViewData = new myViewDataObj();
            myViewData.PageOptionsDropDown =
                  new SelectList(new[] { "10", "15", "25", "50", "100", "1000" }, "15");

            ViewData["myList"] = myViewData.PageOptionsDropDown;
            return View();
        }

e

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

ha funzionato anche se lo fai,

public ActionResult About()
        {
            myViewDataObj myViewData = new myViewDataObj();
            myViewData.PageOptionsDropDown =
                  new SelectList(new[] { "10", "15", "25", "50", "100", "1000" });

            ViewData["myListValues"] = myViewData.PageOptionsDropDown;
            ViewData["myList"] = "15";
            return View();
        }

e

<%=Html.DropDownList("myList",(IEnumerable<SelectListItem>)ViewData["myListValues"]) %>

1

Usando il tuo esempio questo ha funzionato per me:

Controller:

ViewData["PageOptionsDropDown"] = new SelectList(new[] { "10", "15", "25", "50", "100", "1000" }, "15");

Visualizza:

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

Sì, funziona anche per me. Nel mio caso, l'elenco è un oggetto Modello di entità. Controller: ViewData ["Categories"] = new SelectList (db.Categories.ToList (), "CategoryId", "CategoryName", "15"); Visualizza: Html.DropDownList ("CategoryId", (SelectList) ViewData ["Categories"], "--select--")
Junior Mayhé

1
MonthRepository monthRepository = new MonthRepository();
IQueryable<MonthEntity> entities = monthRepository.GetAllMonth();
List<MonthEntity> monthEntities = new List<MonthEntity>();

foreach(var r in entities)
{
    monthEntities.Add(r);
}

ViewData["Month"] = new SelectList(monthEntities, "MonthID", "Month", "Mars");

1

Lo faccio così:

List<SelectListItem> list = new List<SelectListItem>{
new SelectListItem {Selected = true, Text = "Select", Value = "0"},
new SelectListItem {Selected = true, Text = "1", Value = "1"},
new SelectListItem {Selected = true, Text = "2", Value = "2"}
};
return list.ToArray();

ToArray () si occupa dei problemi.


1

Se vuoi passare del testo casuale al tuo DropDownList, ad esempio --Seleziona-- puoi farlo facilmente usando questo codice:

@Html.DropDownListFor(x => x.CategoryId, new SelectList(Model.Categories, "Id", "Name"), "--Select--", new { @class = "form-control" })

0

È possibile che tu abbia qualche ambiguità in ViewData:

Dai un'occhiata qui


0

il valore selezionato nel modello sfrutta invece dell'elemento predefinito. (Sono d'accordo di non aver letto tutti i post)


0

Non riesco a ricordare come sia stato installato mvc 1, ma sembra che volesse che la lista selezionata fosse la stessa del campo a cui apparteneva ...

Quello che ho trovato, come qualcuno ha detto in precedenza, è che i miei elenchi di selezione non funzionavano in mvc2 quando i ViewData sono stati inviati come è stato chiamato lo stesso campo.

Per esempio:

<%= Html.DropDownListFor((model => model.ForID), (SelectList)ViewData["ForName"]) %>

funziona quando

<%= Html.DropDownListFor((model => model.ForID), (SelectList)ViewData["ForID"]) %>

non funziona poiché il nome ViewData "ForID" ha lo stesso nome del campo per cui funziona


0

Una possibile spiegazione è che il valore dell'elenco di selezione a cui si sta legando non è una stringa.

Quindi, in quell'esempio, il parametro 'PageOptionsDropDown' è una stringa nel tuo modello? Perché se non lo è, il valore selezionato nell'elenco non verrebbe mostrato.


0

Se si cerca nel codice sorgente per MVC 2 il metodo di estensione Html.DropDownList, non controlla mai la proprietà SelectedValue della classe SelectList. Tenterà sempre di abbinare il tuo modello.

Tutte le precedenti sono tutte variazioni su un tema, ovvero come inviare un mucchio di dati alla vista per un elenco a discesa e sono tutti buoni l'uno con l'altro (più o meno).

Il problema è nella vista. Crea il tuo metodo di estensione DropDownList che rispetti il ​​valore selezionato che imposti, oppure esegui l'iterazione manuale. Che mai funziona meglio per te.


@Franz Antesberger dice più o meno la stessa cosa.
Simon Halsey,

0

Se hai una collezione nel tuo modello e la tua Vista è fortemente tipizzata, alcune varianti funzioneranno:

@Html.DropDownListFor(x => x.RegionID, 
    new SelectList(Model.Regions,"RegionID", "RegionName", Model.RegionID))

-o-

@Html.DropDownList("RegionID", 
    new SelectList(Model.Regions, "RegionID", "RegionName", Model.RegionID))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.