Element ViewData, który ma klucz „MY KEY”, jest typu „System.String”, ale musi być typu „IEnumerable <SelectListItem>”

142

Próbuję wypełnić listę rozwijaną z bazy danych zmapowanej za pomocą Linq-2-SQL, używając ASP.NET MVC 2 i nadal otrzymuję ten błąd.

Jestem tak zdezorientowany, ponieważ deklaruję zmienną typu IEnumerable<SelectListItem>w drugim wierszu, ale błąd sprawia, że ​​myślę, że tak nie jest. Wydaje mi się, że to powinno być bardzo proste, ale walczę. Każda pomoc jest mile widziana.

Oto interesujące fragmenty mojego kontrolera:

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

A oto interesujące fragmenty mojego poglądu:

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

Oto akcja POST podczas przesyłania formularza

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

Dzięki.

JBibbs
źródło
1
Lista rozwijana pojawia się w widoku w porządku. Wypełnia się z bazy danych tak, jak powinien, ale kiedy wysyłam formularz, otrzymuję te błędy.
JBibbs
6
Podsumowanie zaakceptowanej odpowiedzi: upewnij się, że lista została wypełniona zarówno w akcjach pobierania, jak i publikowania kontrolera. Łatwo o tym zapomnieć, a potem tracić czas na szukanie bardziej skomplikowanego błędu.
Adam Tolley

Odpowiedzi:

208

Miałem ten sam problem i wreszcie uzyskałem odpowiedź ...

Problem polega na tym, że w akcji POST, po przesłaniu formularza, ModelState jest nieprawidłowy lub wyłapuje błąd w try / catch, więc zwracany jest widok. Ale tym razem Widok nie jest ViewData["basetype"]poprawnie ustawiony.

Musisz go ponownie wypełnić, prawdopodobnie tym samym kodem, co wcześniej, więc powtórz to:

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

przed return View(meal)w [HttpPost]metodzie.

dokładnie to rozwiąże twój problem:

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

Wiem, że to pytanie jest bardzo stare, ale przyjechałem tu dzisiaj z tym samym problemem, więc inni mogliby przyjść tu później ...

Peto
źródło
8
+1 dla „zapełnij to ponownie”… Mam dość solidny system do tworzenia moich modeli widoku, ale zupełnie zapomniałem go nazwać. W związku z tym nieruchomość nie była zaludniona i otrzymałem tę (raczej niejednoznaczną) wiadomość bez względu na to, co próbowałem.
Tim Medora,
8
jeśli otrzymujesz to PRZED postem, to dlatego, że nie ma nic w SelectList, po prostu znalazłem ten.
Martin,
1
+1 Ponieważ ustawiałem mój ViewBag w metodzie Index, kiedy naprawdę wywoływałem Html.Action do innej metody akcji !!
SwampyFox
Dzięki. Byłoby miło, gdyby został po prostu zakonserwowany, ale przypuszczam, że nie byłby to „sposób” MVC.
Casey,
jeśli model jest unieważniony, to czy dane przesłane przez użytkownika zostaną zapisane w bazie danych? ja też mam ten sam problem. jestem nowicjuszem. Popraw mnie, jeśli się mylę.
Koushik Saha
87

Ten błąd zostanie wyświetlony, jeśli SelectList ma wartość null.

Ben
źródło
3
Tak, jest to częsty błąd / przeoczenie podczas konfigurowania SelectList na GET, a następnie ogłaszania ModelState.IsValid==falsezwrotnego do akcji POST (oczywiście), która ma, więc zwracasz model, return View(model) ale nie wypełniasz ponownie źródła SelectList przed powrotem z POST. Ponieważ nie ma ViewState ala WebForms, nie ma źródła, z którego @Html.DropDownpomocnik mógłby odbudować selekcję. Musisz wypełnić tę listę źródeł KAŻDY raz, gdy zwracasz widok do klienta, nie tylko na GET.
ryzm
tak, to był mój problem. Zapomniałem wypełnić selectList w wywołaniu get. Bardzo mylący błąd. Wspaniały post.
Matt,
1

Dla przyszłych czytelników, jeśli używasz maszynki do golenia, spróbuj zmienić typ elementu listy wyboru z listy na IEnumerable.

Z

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

Do

@Html.DropDownListFor(m => m.id, ViewBag.SomeList as IEnumerable<SelectListItem>)
sxyplex
źródło
0

Spróbuj dodać ciąg znaków dla nazwy listy rozwijanej jako pierwszy parametr i usuń element ze swoich viewdata:

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

Oto także metoda rozszerzenia, której możesz użyć, aby lista rozwijana była skonfigurowana w podobny sposób, jak w przypadku innych elementów sterujących:

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

Na przykład

<%= Html.DropDownList(x => x.BaseType, (IEnumerable<SelectListItem>)ViewData["basetype"], "")%>
CRice
źródło
0

Ustawiasz kolekcję jako element w słowniku ViewData i próbujesz pobrać ją jako właściwość w modelu. Prostą poprawką byłoby odwołanie się do niego w taki sam sposób, jak go ustawiłeś:

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

Alternatywnie, poniższy kod używa silnie wpisanego widoku:

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

Następnie w swoim silnie wpisanym widoku:

    <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>
Igor Zevaka
źródło
Próbowałem użyć kodu z przykładu „prostej poprawki” i otrzymałem ten sam błąd. Powinienem był wspomnieć, że lista rozwijana zapełnia się w Widoku ok, ale pojawia się ten błąd, kiedy przesyłam formularz.
JBibbs
Czy możesz opublikować kod akcji kontrolera, która obsługuje przesyłanie formularza?
Igor Zevaka
Jasne, dodam to do oryginalnego posta. Dzięki za dotychczasową pomoc.
JBibbs
0

Jeśli używasz Html.DropDownList()metody - ten sam błąd może wystąpić, jeśli element ViewData / Viewbag nie jest ustawiony, jak odpowiedział @Peto.

Ale może nie być ustawiony poprawnie w przypadku elementu zestawu kontrolera, ale w widoku głównym używasz częściowego wywołania viw z nowymi wartościami ViewDataDictionary.

jeśli masz @Html.Partial("Partianame", Model,new ViewDataDictionary() { /* ... */ })to częściowy widok nie będzie widzieć ViewDatai ViewBagdanych, usuń new ViewDataDictionary()parametr

Evgeny Levin
źródło
0

Przyszłym czytelnikom,

Natknąłem się dzisiaj na problem i nie mogłem go naprawić. W końcu okazało się to naprawdę proste. Pracowałem ze stołem + widokiem. Kiedy zaktualizowałem tabelę (dodałem kilka kolumn), zapomniałem zaktualizować (upuścić i odtworzyć) widok, co spowodowało u mnie problem. Mam nadzieję, że to komuś pomoże.

Mariano Gianni
źródło
0

Mam dzisiaj ten sam błąd i moim rozwiązaniem jest „poprawność” modelu.

W moim przypadku po przesłaniu przez użytkownika kliknięciem „zapisz” otrzymałem stan modelu: nieprawidłowy, jeśli użytkownik wprowadził „0”, ale stan modelu będzie ważny, jeśli użytkownik wprowadzi „0,0”.

Dlatego nadpisuję metodę „IsValid”, aby zwracała wartość true, nawet wpisaną przez użytkownika wartość „0”.

Mam nadzieję, że to pomoże.

Ray Chung
źródło