L'élément ViewData qui a la clé 'ma clé' est de type ' System.String 'mais doit être de type' IEnumerable '

J'essaie de remplir une liste déroulante à partir d'une base de données mappée avec Linq-2-SQL, en utilisant ASP.NET MVC 2, et continuez à obtenir cette erreur.

Je suis tellement confus parce que je déclare une variable de type IEnumerable<SelectListItem> sur la deuxième ligne, mais l'erreur me fait penser que ce n'est pas le cas. Je pense que cela devrait être très simple, mais je me bats. Toute aide est appréciée.

Voici les bits intéressants de mon contrôleur:

public ActionResult Create()
{
    var db = new DB();
    IEnumerable<SelectListItem> basetypes = db.Basetypes.Select(
        b => new SelectListItem { Value = b.basetype, Text = b.basetype });
    ViewData["basetype"] = basetypes;
    return View();
}

Et voici les morceaux intéressants de mon vue:

<div class="editor-label">
   <%: Html.LabelFor(model => model.basetype) %>
</div>
<div class="editor-field">
   <%: Html.DropDownList("basetype") %>
   <%: Html.ValidationMessageFor(model => model.basetype) %>
</div>

Voici L'action POST lors de la soumission du formulaire

// POST: /Meals/Create
[HttpPost]
public ActionResult Create(Meal meal)
{
    if (ModelState.IsValid)
    {
        try
        {
            // TODO: Add insert logic here
            var db = new DB();
            db.Meals.InsertOnSubmit(meal);
            db.SubmitChanges();
            return RedirectToAction("Index");
        }
        catch
        {
            return View(meal);
        }
    }
    else
    {
        return View(meal);
    }
}

Merci.

136
demandé sur sharptooth 2010-08-03 08:09:39

8 réponses

J'ai eu le même problème, et finalement j'ai eu la réponse...

Le problème est que dans L'action POST, Après avoir soumis le formulaire, ModelState n'est pas valide, ou il attrape une erreur dans try/catch, donc la vue est renvoyée. Mais cette fois, la vue n'a pas le {[2] } correctement défini.

Vous devez le remplir à nouveau, probablement avec le même code utilisé auparavant, alors répétez ceci:

var db = new DB();
IEnumerable<SelectListItem> basetypes = db.Basetypes.Select(
    b => new SelectListItem { Value = b.basetype, Text = b.basetype });
ViewData["basetype"] = basetypes;

Avant le return View(meal) dans la méthode [HttpPost].

Exactement cela va résoudre votre problème:

[HttpPost]
public ActionResult Create(Meal meal)
{
    if (ModelState.IsValid)
    {
        try
        {
            // TODO: Add insert logic here
            var db = new DB();
            db.Meals.InsertOnSubmit(meal);
            db.SubmitChanges();
            return RedirectToAction("Index");
        }
        catch
        {
            var db = new DB();
            IEnumerable<SelectListItem> basetypes = db.Basetypes.Select(
               b => new SelectListItem { Value = b.basetype, Text = b.basetype });
            ViewData["basetype"] = basetypes;
            return View(meal);
        }
    }
    else
    {
        var db = new DB();
        IEnumerable<SelectListItem> basetypes = db.Basetypes.Select(
            b => new SelectListItem { Value = b.basetype, Text = b.basetype });
        ViewData["basetype"] = basetypes;
        return View(meal);
    }
}

Je sais que cette question est très ancienne, mais je suis venu ici aujourd'hui avec le même problème, donc d'autres pourraient venir ici plus tard...

200
répondu Peto 2013-07-26 09:20:17

Vous recevrez cette erreur si la SelectList est null.

82
répondu Ben 2014-10-08 19:15:40

Je viens de rencontrer ce problème et cet article m'a aidé à le surmonter - http://odetocode.com/Blogs/scott/archive/2010/01/18/drop-down-lists-and-asp-net-mvc.aspx

La cause la plus probable que votre collection soit repeuplée après le po

3
répondu Michael 2011-04-04 11:58:30

Essayez d'ajouter une chaîne pour le nom de votre liste déroulante en tant que premier paramètre, et obtenez l'élément de votre viewdata:

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

Voici également une méthode d'extension que vous pouvez utiliser pour que la liste déroulante soit configurée dans un style similaire à celui de vos autres contrôles:

        public static string DropDownList<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, string optionLabel)
        where TModel : class
    {
        string inputName = ExpressionHelper.GetInputName(expression);
        return htmlHelper.DropDownList(inputName, selectList, optionLabel);
    }

Par exemple

<%= Html.DropDownList(x => x.BaseType, (IEnumerable<SelectListItem>)ViewData["basetype"], "")%>
0
répondu CRice 2010-08-03 04:20:33

Vous définissez la collection en tant qu'élément dans le dictionnaire ViewData et essayez de la récupérer en tant que propriété sur le modèle. Une solution simple serait de référence de la même manière que vous le configurer:

    <%var basetype = ViewData["basetype"] as IEnumerable<SelectListItem>;%>
    <div class="editor-label">
        <%: Html.Label("basetype") %>
    </div>
    <div class="editor-field">
        <%: Html.DropDownList("basetype", basetype) %>
        <%: Html.ValidationMessage("basetype") %>
    </div>

Alternativement, le code ci-dessous utilise une vue fortement typée:

public class ViewModel {
   //Model properties
   public IEnumerable<SelectListItem> basetype {get;set;}
}

public ActionResult Create()
    {
        var db = new DB();
        IEnumerable<SelectListItem> basetypes = db.Basetypes.Select(b => new SelectListItem { Value = b.basetype, Text = b.basetype });
        return View(new ViewModel { basetype=basetypes });
    }

Ensuite, dans votre vue fortement typée:

    <div class="editor-label">
        <%: Html.LabelFor(model => model.basetype) %>
    </div>
    <div class="editor-field">
        <%: Html.DropDownListFor(model=>model.basetype) %>
        <%: Html.ValidationMessageFor(model => model.basetype) %>
    </div>
0
répondu Igor Zevaka 2010-08-03 04:26:35

Si vous utilisez la méthode Html.DropDownList(), la même erreur peut se produire si votre élément ViewData / Viewbag n'est pas défini, car @ Peto a répondu.

Mais il peut ne pas être défini dans le cas d'un élément de jeu de contrôleur correctement, mais dans la vue principale, vous utilisez un appel VIW partiel avec de nouvelles valeurs ViewDataDictionary.

Si vous avez @Html.Partial("Partianame", Model,new ViewDataDictionary() { /* ... */ }) alors votre vue partielle ne verra pas les données ViewData et ViewBag, supprimez le paramètre new ViewDataDictionary()

0
répondu Evgeny Levin 2013-10-17 14:59:59

Aux futurs lecteurs,

Je suis tombé sur le problème aujourd'hui et je ne pouvais pas le résoudre. Il s'est avéré être vraiment simple après tout. Je travaillais avec une table + vue. Lorsque j'ai mis à jour la table (ajouté quelques colonnes), j'ai oublié de mettre à jour (supprimer et recréer) la vue, ce qui a causé le problème pour moi. Espérons que cela aide quelqu'un.

0
répondu Mariano Gianni 2017-10-03 18:26:20

Pour les futurs lecteurs, si vous utilisez razor, essayez de changer le type d'élément selectlist de List en IEnumerable.

De

@Html.DropDownListFor(m => m.id, ViewBag.SomeList as List<SelectListItem>)

À

@Html.DropDownListFor(m => m.id, ViewBag.SomeList as IEnumerable<SelectListItem>)
0
répondu sxyplex 2018-07-27 14:49:05