web-dev-qa-db-fra.com

Comment puis-je faire en sorte que cette liste de sélection ASP.NET MVC fonctionne?

Je crée une liste de sélection dans mon contrôleur, à afficher dans la vue.

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

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

Ca 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 comment aucun élément n'est sélectionné?

Comment puis-je réparer cela??

125
Pure.Krome

Voici comment je le 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 second regard, je ne suis pas sûr de savoir ce que vous recherchez ...

127
mhenrixon

J'utilise une méthode d'extension:

tilisation

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;
    }
}
68
Thomas Stock

Utilisation du constructeur qui accepte items, dataValueField, dataTextField, selectedValue en tant que paramètres:

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

Alors à votre avis:

<%=Html.DropDownList("myList") %>
48
Çağdaş Tekin

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

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 désirée - vous pouvez bien sûr laisser de côté le "(Select one)" 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 code révisée peut être trouvée ici avec des commentaires XML.

18
JustinStolle

Le problème est que SelectList fonctionne comme prévu. Le bug 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 GetEnumerator () (ou si Mvc le fait pour vous). MVC créera de nouveaux SelectListItems.

Vous devez utiliser le gestionnaire SelectList avec le SelectListItem [], le Text-Name, le Value-Name et le SelectedValue. N'oubliez pas de transmettre à SelectedValue la VALEUR de SelectListItem que vous souhaitez sélectionner et non 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)

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

13
Franz Antesberger

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" },
}
11
murki

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

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

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

Exemple:

En supposant que notre objet Region ressemble à ceci:

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

Et votre modèle de vue ressemble à 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")) 

Seulement si vous substituez la méthode ToString de l'objet Region à quelque chose comme:

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

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

Cela garantit à 100% de travailler.

Mais je crois vraiment que le meilleur moyen de faire en sorte que SelectList 100% fonctionne dans toutes les circonstances consiste à utiliser la méthode Equals pour tester la valeur de la propriété DropDownList ou ListBox par rapport à chaque élément de la collection d'éléments.

7
ararog

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

C’est certes un peu étrange, mais j’ai essayé et ça marche.

Donc, si votre classe a un champ appelé CountryId say 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 la publication, vous pouvez faire quelque chose avec Collection ["CountryName"] .

5
Adam

J'ai eu exactement le même problème. La solution est simple Il suffit de changer le paramètre "name" transmis à l’assistant DropDownList par un élément 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- voir

Je cite le Dan Watson:

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

à votre santé!

4
cleftheris

Facile:

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

Toutes ces réponses ont l'air géniales, mais il semble que le contrôleur prépare les données d'une vue dans un format structuré bien connu, au lieu 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 renvoyer l'élément sélectionné via un paramètre d'action. Oui non pourquoi pas Séparation des préoccupations, oui? Cela semble étrange que le contrôleur construise quelque chose de spécifique pour l'interface utilisateur et la vue.

3
slimflem

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"]) %>
2
Tony Borf
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
Cactus

Si vous voulez transmettre un texte aléatoire à votre DropDownList, par exemple - Select - vous pouvez le faire facilement en utilisant le code suivant:

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

Je le fais 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();

ToArray () prend en charge les problèmes.

1
femseks

En utilisant votre exemple cela a fonctionné pour moi:

contrôleur:

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

vue:

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

Si vous examinez le code source de MVC 2 avec la méthode d'extension Html.DropDownList, il ne vérifie jamais la propriété SelectedValue de la classe SelectList. Il ne tentera jamais que de faire correspondre votre modèle.

Tout ce qui précède représente toutes les variations d'un thème. Comment envoyer une série de données à la vue sous forme de liste déroulante et qui sont toutes aussi bonnes les unes 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-la à la main. Ce qui fonctionne le mieux pour vous.

0
Simon Halsey

Si vous avez une collection dans votre modèle et que votre vue est fortement dactylographiée, certaines variantes fonctionneront:

@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))
0
Mark

Je ne me souviens plus comment mvc 1 avait été configuré, mais il semble que la liste de sélection ait été nommée de la même manière que le champ auquel elle appartenait également ...

Ce que j’ai trouvé, comme l’a dit un peu le type ci-dessus, c’est que mes listes de sélection ne fonctionnaient pas dans mvc2 lorsque le ViewData auquel elles étaient envoyées était nommé de la même manière que 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" porte le même nom que le champ pour lequel il travaille

0
Mark

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

Ainsi, dans cet exemple, le paramètre "PageOptionsDropDown" est-il une chaîne dans votre modèle? Parce que sinon, la valeur sélectionnée dans la liste ne serait pas affichée.

0
FruitDealer

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

0
Daniel

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

Jetez un oeil ici

0
KP.