Comment puis-je faire fonctionner cette SelectList ASP.NET MVC?

126

Je crée une selectList dans mon contrôleur, à afficher dans la vue.

J'essaye de le créer à la volée, en quelque sorte ... comme ça ...

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

Il compile, mais la sortie est mauvaise ...

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

Remarquez qu'aucun élément n'est sélectionné?

Comment puis-je réparer cela??

Pure.Krome
la source
1
Six réponses ... une mise en favoris ... pas de votes positifs: / Je vais lui donner un +1
womp

Réponses:

128

C'est comme ça que je fais

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

Au deuxième coup d'œil, je ne suis pas sûr de savoir ce que vous recherchez ...

mhenrixon
la source
2
Merci cela m'a aidé à comprendre ce truc.
Cadoo
6
Ne résout pas le problème de l'élément sélectionné, mais c'est un excellent moyen d'éviter les chaînes magiques pour les listes de sélection! Cheers
Alan Christensen
11
Pour résoudre le problème de l'élément sélectionné, ajoutez le code suivant: SelectList sList = new SelectList(selectList, "Text", "Value", selected);selectedest le client actuellement sélectionné
jao
68

J'utilise une méthode d'extension:

usage

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

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

avec

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
la source
agréable. J'ai ajouté un Func sélectionné, une option defaultValue et une deuxième surcharge sans aucune valeur par défaut à spécifier et cela fonctionne un régal. En passant, si vous voulez rendre le type de retour IEnumerable <SelectListItem>, vous pouvez utiliser la syntaxe de retour de rendement pour rendre ce look vraiment propre
Chris Meek
48

En utilisant le constructeur qui accepte items, dataValueField, dataTextField, selectedValuecomme paramètres:

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

Ensuite, à votre avis:

<%=Html.DropDownList("myList") %>
Çağdaş Tekin
la source
3
gentil mec :) j'aime! J'essayais de faire ça .. mais je n'ai pas pu obtenir la partie .Select (..) .. sympa :) Je vais l'essayer à la maison, plus tard :)
Pure.Krome
1
Heya Cagdas. fonctionne très bien, sauf que le champ sélectionné n'est pas sélectionné. une idée? est-ce un bug dans les trucs MVC?
Pure.Krome
2
L'élément sélectionné fonctionne lorsque vous ajoutez l'élément SelectList dans l'objet ViewData (comme dans ViewData ["myList"] = new SelectList ..) et que vous l'avez ensuite rendu avec <% = Html.DropDownList ("myList")%>. Je ne pouvais pas faire fonctionner l'élément sélectionné sans le faire de cette façon. Bizarre.
Çağdaş Tekin
@Cagdas - salut encore mec .. je n'ai toujours pas compris ça :( Qu'est-ce que c'est à propos d'un ViewData ??? J'ai un ViewData fortement typé avec sa propre propriété .... ???
Pure.Krome
@ Pure.Krome - J'ai pris cette propriété de votre exemple dans la question. J'édite maintenant l'exemple de code. Veuillez consulter ma modification dans quelques secondes.
Çağdaş Tekin
19

En m'appuyant sur la réponse de Thomas Stock, j'ai créé ces ToSelectListméthodes surchargées :

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

Dans votre contrôleur, vous pouvez effectuer les opérations suivantes:

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

Et enfin dans votre vue, mettez:

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

Il en résultera la sortie souhaitée - bien sûr, vous pouvez "(Select one)"omettre l' optionLabel ci-dessus si vous ne voulez pas le premier élément vide:

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

Mise à jour: Une liste de codes révisée peut être trouvée ici avec des commentaires XML.

JustinStolle
la source
13

Le problème est que SelectList fonctionne comme prévu. Le bogue est dans la conception. Vous pouvez définir la propriété sélectionnée dans SelectedItem, mais cela sera complètement ignoré si vous parcourez la liste avec le GetEnumerator () (ou si Mvc le fait pour vous). Mvc créera à la place de nouveaux SelectListItems.

Vous devez utiliser le ctor SelectList avec le SelectListItem [], le Text-Name, le Value-Name et le SelectedValue. Soyez conscient de passer en tant que SelectedValue la valeur de SelectListItem, que vous souhaitez sélectionner, pas le SelectListItem lui-même! Exemple:

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

(pas testé cela, mais j'ai eu le même problème)

puis la 2ème option obtiendra l'attribut selected = "selected". Cela ressemble à de bons vieux DataSets ;-)

Codage terminé
la source
11

Ceci est une 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
la source
new SelectListItem {Selected = true, Text = "15", Value = "15"} pour la valeur sélectionnée.
Cadoo
oups, ouais, j'ai oublié d'inclure la propriété 'Sélectionnée', merci Cadoo =)
murki
10

Si c'est littéralement tout ce que vous voulez faire, déclarer simplement le tableau en tant que chaîne résout le problème de l'élément sélectionné:

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

Il est très simple de faire en sorte que SelectList et SelectedValue fonctionnent ensemble, même si votre propriété n'est pas un objet simple comme une valeur Int, String ou Double.

Exemple:

En supposant que notre objet Region est quelque chose comme ceci:

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

Et votre modèle de vue est quelque chose comme:

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

Vous pouvez avoir le code ci-dessous:

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

Uniquement si vous remplacez la méthode ToString de l'objet Region par quelque chose comme:

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

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

Cela a 100% de garantie de fonctionner.

Mais je crois vraiment que le meilleur moyen de faire fonctionner SelectList à 100% dans toutes les situations est d'utiliser la méthode Equals pour tester la valeur de propriété DropDownList ou ListBox contre chaque élément de la collection d'éléments.

ararog
la source
5

Il semble que si vous avez une vue fortement typée, vous devez changer l'ID de la liste déroulante afin qu'il ne soit PAS le nom d'une propriété sur la classe héritée. Vous devez ensuite mettre une logique dans votre méthode d'édition (POST) pour extraire la valeur sélectionnée de FORMCollection et la mettre sur votre instance avant de valider vos modifications.

C'est certainement un peu étrange, mais je l'ai essayé et ça marche.

Donc, si votre classe a un champ appelé CountryId, et que vous affichez une liste de noms de pays, faites en sorte que la liste déroulante ait un identifiant de CountryName plutôt que CountryId, puis dans le message, vous pouvez faire quelque chose avec Collection ["CountryName"] .


la source
1
Oui, j'ai eu ce même problème. Changer simplement le nom a fonctionné. Merci!
davekaro
4

J'ai eu exactement le même problème. La solution est simple. Changez simplement le paramètre "name" passé à l'assistant DropDownList en quelque chose qui ne correspond à aucune des propriétés existantes dans votre ViewModel. en savoir plus ici: http://www.dotnetguy.co.uk/post/2009/06/25/net-mvc-selectlists-selected-value-does-not-get-set-in-the-view

Je cite le Dan Watson:

Dans MVC, si la vue est fortement typée, l'option sélectionnée de la liste de sélection sera remplacée et la propriété d'option sélectionnée définie sur le constructeur n'atteindra jamais la vue et la première option de la liste déroulante sera sélectionnée à la place (pourquoi est encore un peu un mystère) .

à votre santé!

fente
la source
3

Toutes ces réponses ont l'air bien, mais il semble que le contrôleur prépare les données pour une vue dans un format structuré bien connu plutôt que de laisser la vue itérer simplement un IEnumerable <> fourni via le modèle et créer une liste de sélection standard, puis laisser DefaultModelBinder vous livrer l'élément sélectionné via un paramètre d'action. Oui, non, pourquoi pas? Séparation des préoccupations, oui? Cela semble étrange d'avoir le contrôleur pour créer quelque chose d'aussi spécifique à l'interface utilisateur et à la vue.


la source
3

Facile:

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

Je l'ai juste couru comme ça et je n'ai eu aucun problème,

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

et

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

cela a également fonctionné si vous faites cela,

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

et

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

En utilisant votre exemple, cela a fonctionné pour moi:

manette:

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

vue:

<%= Html.DropDownList("PageOptionsDropDown")%>
Cadoo
la source
Oui, cela fonctionne aussi pour moi. Dans mon cas, la liste est un objet Entity Model. Contrôleur: ViewData ["Categories"] = new SelectList (db.Categories.ToList (), "CategoryId", "CategoryName", "15"); Afficher: 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");
Cactus
la source
1

Je fais ça comme ça:

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

Le ToArray () s'occupe des problèmes.

femseks
la source
1

Si vous souhaitez transmettre du texte aléatoire à votre DropDownList, par exemple --Select-- vous pouvez facilement le faire en utilisant ce code:

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

Il se peut que vous ayez une certaine ambiguïté dans votre ViewData:

Jetez un oeil ici

KP.
la source
0

la valeur sélectionnée dans le modèle profite au lieu de l'élément par défaut. (Je suis d'accord, je n'ai pas lu tous les messages)

Daniel
la source
0

Je ne me souviens pas comment mvc 1 a été configuré, mais il semble qu'il voulait que la liste de sélection soit nommée de la même manière que le champ auquel elle appartenait ...

Ce que j'ai trouvé, comme quelqu'un l'a dit ci-dessus, c'est que mes listes de sélection ne fonctionnaient pas dans mvc2 lorsque les ViewData qu'elles avaient été envoyées étaient nommées comme le champ.

Par exemple:

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

fonctionne quand

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

ne fonctionne pas car le nom ViewData "ForID" est nommé de la même manière que le champ pour lequel il travaille

marque
la source
0

Une explication possible est que la valeur de la liste de sélection à laquelle vous liez n'est pas une chaîne.

Dans cet exemple, le paramètre «PageOptionsDropDown» est-il une chaîne dans votre modèle? Parce que si ce n'est pas le cas, la valeur sélectionnée dans la liste ne sera pas affichée.

Marchand de fruits
la source
0

Si vous recherchez dans le code source de MVC 2 la méthode d'extension Html.DropDownList, il ne vérifie jamais la propriété SelectedValue de la classe SelectList. Il n'essaiera jamais de correspondre à votre modèle.

Tout ce qui précède sont toutes des variations sur un thème, c'est-à-dire comment envoyer un tas de données à la vue pour une liste déroulante et ils sont tous aussi bons les uns que les autres (plus ou moins).

Le problème est dans la vue. Créez votre propre méthode d'extension DropDownList qui respecte la valeur de sélection que vous avez définie ou effectuez une itération à la main. Ce qui fonctionne le mieux pour vous.

Simon Halsey
la source
@Franz Antesberger dit à peu près la même chose.
Simon Halsey
0

Si vous avez une collection dans votre modèle et que votre vue est fortement typée, une variation de ceci fonctionnera:

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

-ou-

@Html.DropDownList("RegionID", 
    new SelectList(Model.Regions, "RegionID", "RegionName", Model.RegionID))
marque
la source