Wie kann ich diese ASP.NET MVC SelectList zum Laufen bringen?

126

Ich erstelle eine Auswahlliste in meinem Controller, um sie in der Ansicht anzuzeigen.

Ich versuche es im laufenden Betrieb zu erstellen, irgendwie ... so ...

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

Es wird kompiliert, aber die Ausgabe ist schlecht ...

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

Beachten Sie, wie kein Artikel ausgewählt ist?

Wie kann ich das beheben?

Pure.Krome
quelle
1
Sechs Antworten ... eine favorisiert ... keine positiven Stimmen: / Ich gebe ihm eine +1
Womp

Antworten:

128

So mache ich es

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()
    };

Auf den zweiten Blick bin ich mir nicht sicher, ob ich weiß, wonach Sie suchen ...

Mhenrixon
quelle
2
Danke, das hat mir geholfen, dieses Zeug herauszufinden.
Cadoo
6
Behebt das Problem mit ausgewählten Elementen nicht, aber es ist eine großartige Möglichkeit, magische Zeichenfolgen für ausgewählte Listen zu vermeiden! Prost
Alan Christensen
11
Um das ausgewählte Element Problem zu beheben, fügen Sie den folgenden Code ein : SelectList sList = new SelectList(selectList, "Text", "Value", selected);wo selectedist die aktuell ausgewählte Kunden
jao
68

Ich benutze eine Erweiterungsmethode:

Verwendung

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

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

mit

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;
    }
}
Thomas Stock
quelle
nett. Ich habe einen ausgewählten Func, eine defaultValue-Option und eine zweite Überladung hinzugefügt, ohne dass Standardeinstellungen angegeben werden müssen, und dies ist ein Vergnügen. Übrigens, wenn Sie den Rückgabetyp IEnumerable <SelectListItem> machen möchten, können Sie die Ertragsrückgabesyntax verwenden, um diesen Look wirklich sauber zu machen
Chris Meek
48

Verwenden des Konstruktors, der items, dataValueField, dataTextField, selectedValueals Parameter akzeptiert :

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

Dann aus Ihrer Sicht:

<%=Html.DropDownList("myList") %>
Çağdaş Tekin
quelle
3
netter Kerl :) Ich mag! Ich habe versucht, dies zu tun .. aber ich konnte den .Select (..) Teil nicht bekommen .. schön :) Ich werde es später zu Hause ausprobieren :)
Pure.Krome
1
Heya Cagdas. funktioniert hervorragend, außer dass das ausgewählte Feld nicht ausgewählt ist. irgendeine Idee? Ist das ein Fehler im MVC-Zeug?
Pure.Krome
2
Das ausgewählte Element funktioniert, wenn Sie das SelectList-Element zum ViewData-Objekt hinzufügen (wie in ViewData ["myList"] = new SelectList ..) und es dann mit <% = Html.DropDownList ("myList")%> rendern. Ich konnte das ausgewählte Element nicht zum Laufen bringen, ohne es auf diese Weise zu tun. Seltsam.
Çağdaş Tekin
@Cagdas - Hallo nochmal, Alter .. ich habe das immer noch nicht herausgefunden :( Was ist das mit einer ViewData ??? Ich habe eine stark typisierte ViewData mit eigener Eigenschaft .... ???
Pure.Krome
@ Pure.Krome - Ich habe diese Eigenschaft aus Ihrem Beispiel in der Frage übernommen. Jetzt bearbeite ich das Codebeispiel. Bitte sehen Sie meine Bearbeitung in ein paar Sekunden.
Çağdaş Tekin
19

Aufbauend auf der Antwort von Thomas Stock habe ich diese überladenen ToSelectListMethoden erstellt:

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())
            };
        }
    }
}

In Ihrem Controller können Sie Folgendes tun:

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

Und schließlich setzen Sie in Ihrer Ansicht:

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

Dies führt zu der gewünschten Ausgabe. Natürlich können Sie das "(Select one)"obige optionLabel weglassen, wenn Sie das erste leere Element nicht möchten:

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

Update: Eine überarbeitete Codeliste mit XML-Kommentaren finden Sie hier .

JustinStolle
quelle
13

Das Problem ist, dass SelectList wie geplant funktioniert. Der Fehler liegt im Design. Sie können die Selected-Eigenschaft in SelectedItem festlegen, dies wird jedoch vollständig ignoriert, wenn Sie die Liste mit dem GetEnumerator () durchlaufen (oder wenn Mvc dies für Sie erledigt). Mvc erstellt stattdessen neue SelectListItems.

Sie müssen den SelectList-Code mit dem SelectListItem [], dem Textnamen, dem Wertnamen und dem SelectedValue verwenden. Achten Sie darauf, den Wert von SelectListItem, den Sie auswählen möchten, als SelectedValue zu übergeben, nicht das SelectListItem selbst! Beispiel:

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" );

(nicht getestet, aber ich hatte das gleiche Problem)

dann erhält die 2. Option das Attribut selected = "selected". Das sieht nach guten alten DataSets aus ;-)

Codierung weg
quelle
11

Dies ist eine Option:

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" },
}
Murki
quelle
neues SelectListItem {Selected = true, Text = "15", Value = "15"} für den ausgewählten Wert.
Cadoo
oops, yeah, habe vergessen, 'Selected' -Eigenschaft aufzunehmen, danke Cadoo =)
murki
10

Wenn das buchstäblich alles ist, was Sie tun möchten, behebt das Deklarieren des Arrays als Zeichenfolge das Problem mit dem ausgewählten Element:

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

Es ist sehr einfach, SelectList und SelectedValue zusammenzubringen, selbst wenn Ihre Eigenschaft kein einfaches Objekt wie ein Int-, String- oder Double-Wert ist.

Beispiel:

Angenommen, unser Region-Objekt sieht ungefähr so ​​aus:

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

Und Ihr Ansichtsmodell ist so etwas wie:

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

Sie können den folgenden Code haben:

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

Nur wenn Sie die ToString-Methode des Region-Objekts auf Folgendes überschreiben:

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

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

Diese haben 100% Garantie zu arbeiten.

Aber ich glaube wirklich, dass der beste Weg, um SelectList zu 100% in allen Situationen zum Laufen zu bringen, darin besteht, die Equals-Methode zu verwenden, um den DropDownList- oder ListBox-Eigenschaftswert für jedes Element in der Elementauflistung zu testen.

Ararog
quelle
5

Wenn Sie eine stark typisierte Ansicht haben, müssen Sie anscheinend die ID der Dropdown-Liste so ändern, dass sie NICHT der Name einer Eigenschaft in der geerbten Klasse ist. Anschließend müssen Sie Ihrer POST-Methode (Edit) eine Logik hinzufügen, um den ausgewählten Wert aus der FORMCollection abzurufen und in Ihre Instanz einzufügen, bevor Sie Ihre Änderungen übernehmen.

Das ist sicherlich ein bisschen seltsam, aber ich habe es versucht und es funktioniert.

Wenn Ihre Klasse also ein Feld mit dem Namen "CountryId" hat und Sie eine Liste mit Ländernamen anzeigen, lassen Sie die Dropdown-Liste die ID "CountryName" anstelle von "CountryId" haben. In diesem Beitrag können Sie mit "Collection [" CountryName "] etwas tun. .


quelle
1
Ja, ich hatte das gleiche Problem. Einfach den Namen zu ändern hat funktioniert. Vielen Dank!
Davekaro
4

Ich hatte genau das gleiche Problem. Die Lösung ist einfach. Ändern Sie einfach den an den DropDownList-Helfer übergebenen Parameter "name" in einen Parameter, der keiner der in Ihrem ViewModel vorhandenen Eigenschaften entspricht. Lesen Sie hier mehr: http://www.dotnetguy.co.uk/post/2009/06/25/net-mvc-selectlists-selected-value-does-not-get-set-in-the-view

Ich zitiere den Dan Watson:

Wenn in MVC die Ansicht stark typisiert ist, wird die ausgewählte Option der Auswahlliste überschrieben und die im Konstruktor festgelegte Eigenschaft der ausgewählten Option erreicht die Ansicht nie. Stattdessen wird die erste Option in der Dropdown-Liste ausgewählt (warum ist dies immer noch ein Rätsel). .

Prost!

Cleftheris
quelle
3

Alle diese Antworten sehen gut aus, aber es scheint, dass der Controller Daten für eine Ansicht in einem bekannten strukturierten Format vorbereitet, anstatt die Ansicht einfach eine über das Modell gelieferte IEnumerable <> iterieren zu lassen und eine Standardauswahlliste zu erstellen und dann DefaultModelBinder zu lassen Liefern Sie den ausgewählten Artikel über einen Aktionsparameter an Sie zurück. Ja, nein, warum nicht? Trennung von Bedenken, ja? Scheint seltsam, wenn der Controller etwas so UI- und View-spezifisch erstellt.


quelle
3

Einfach:

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

Ich habe es einfach so gemacht und hatte keine Probleme,

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();
        }

und

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

es hat auch funktioniert, wenn Sie dies tun,

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();
        }

und

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

Anhand Ihres Beispiels hat dies bei mir funktioniert:

Regler:

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

Aussicht:

<%= Html.DropDownList("PageOptionsDropDown")%>
Cadoo
quelle
Ja, das funktioniert auch bei mir. In meinem Fall ist die Liste ein Entitätsmodellobjekt. Controller: ViewData ["Categories"] = neue SelectList (db.Categories.ToList (), "CategoryId", "CategoryName", "15"); Ansicht: 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");
Kaktus
quelle
1

So mach ich es:

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();

Das ToArray () kümmert sich um die Probleme.

Femseks
quelle
1

Wenn Sie zufälligen Text an Ihre DropDownList übergeben möchten, z. B. --Select-- , können Sie dies einfach mit folgendem Code tun:

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

Es kann vorkommen, dass Ihre ViewData mehrdeutig sind:

Schauen Sie hier

KP.
quelle
0

Der im Modell ausgewählte Wert wird anstelle des Standardelements verwendet. (Ich bin damit einverstanden, dass ich nicht alle Beiträge gelesen habe)

Daniel
quelle
0

Ich kann mich nicht erinnern, wie mvc 1 eingerichtet wurde, aber es scheint, dass die Auswahlliste den gleichen Namen haben soll wie das Feld, zu dem sie gehörte ...

Wie oben erwähnt, stellte ich fest, dass meine Auswahllisten in mvc2 nicht funktionierten, als die ViewData, unter denen sie gesendet wurden, den gleichen Namen wie das Feld hatten.

Beispielsweise:

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

funktioniert wenn

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

funktioniert nicht, da der ViewData-Name "ForID" den gleichen Namen hat wie das Feld, für das er arbeitet

Kennzeichen
quelle
0

Eine mögliche Erklärung ist, dass der Auswahllistenwert, an den Sie binden, keine Zeichenfolge ist.

Ist der Parameter 'PageOptionsDropDown' in diesem Beispiel eine Zeichenfolge in Ihrem Modell? Wenn dies nicht der Fall ist, wird der ausgewählte Wert in der Liste nicht angezeigt.

FruitDealer
quelle
0

Wenn Sie im Quellcode für MVC 2 nach der Erweiterungsmethode Html.DropDownList suchen, wird die SelectedValue-Eigenschaft der SelectList-Klasse niemals überprüft. Es wird immer nur versucht, mit Ihrem Modell übereinzustimmen.

Alle oben genannten sind Variationen eines Themas, dh wie senden Sie eine Reihe von Daten an die Ansicht, um eine Dropdown-Liste zu erhalten, und sie sind alle so gut wie einander (mehr oder weniger).

Das Problem liegt in der Ansicht. Erstellen Sie entweder Ihre eigene DropDownList-Erweiterungsmethode, die den von Ihnen festgelegten Auswahlwert berücksichtigt, oder iterieren Sie manuell. Was für Sie am besten funktioniert.

Simon Halsey
quelle
@ Franz Antesberger sagt fast das Gleiche.
Simon Halsey
0

Wenn Sie eine Sammlung in Ihrem Modell haben und Ihre Ansicht stark typisiert ist, funktioniert eine Variation davon:

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

-oder-

@Html.DropDownList("RegionID", 
    new SelectList(Model.Regions, "RegionID", "RegionName", Model.RegionID))
Kennzeichen
quelle