2015-12-19 12 views
46

Ho il seguente modello vistaL'elemento Viewdata che ha la chiave 'XXX' è di tipo 'System.Int32' ma deve essere di tipo 'IEnumerable <SelectListItem>'

public class ProjectVM 
{ 
    .... 
    [Display(Name = "Category")] 
    [Required(ErrorMessage = "Please select a category")] 
    public int CategoryID { get; set; } 
    public IEnumerable<SelectListItem> CategoryList { get; set; } 
    .... 
} 

e il seguente metodo controllore per creare un nuovo progetto e assegnare un Category

public ActionResult Create() 
{ 
    ProjectVM model = new ProjectVM 
    { 
     CategoryList = new SelectList(db.Categories, "ID", "Name") 
    } 
    return View(model); 
} 

public ActionResult Create(ProjectVM model) 
{ 
    if (!ModelState.IsValid) 
    { 
     return View(model); 
    } 
    // Save and redirect 
} 

e nella vista

@model ProjectVM 
.... 
@using (Html.BeginForm()) 
{ 
    .... 
    @Html.LabelFor(m => m.CategoryID) 
    @Html.DropDownListFor(m => m.CategoryID, Model.CategoryList, "-Please select-") 
    @Html.ValidationMessageFor(m => m.CategoryID) 
    .... 
    <input type="submit" value="Create" /> 
} 

La vista mostra correttamente, ma al momento della presentazione del modulo, ricevo il seguente messaggio di errore

InvalidOperationException: L'elemento Viewdata che ha la chiave 'IDCategoria' è di tipo 'System.Int32' ma deve essere di tipo 'IEnumerable <SelectListItem> '.

Lo stesso errore si verifica con il metodo @Html.DropDownList(), e se passo il SelectList utilizzando un ViewBag o ViewData.

risposta

46

L'errore indica che il valore di CategoryList è nullo (e di conseguenza il metodo DropDownListFor() aspetta che il primo parametro è di tipo IEnumerable<SelectListItem>).

Non stanno generando un ingresso per ogni proprietà di ogni SelectListItem a CategoryList (e non si dovrebbe) in modo da non valori per la SelectList sono pubblicati al metodo di controllo, e quindi il valore del model.CategoryList nel metodo POST è null. Se restituisci la vista, devi prima riassegnare il valore di CategoryList, proprio come hai fatto nel metodo GET.

public ActionResult Create(ProjectVM model) 
{ 
    if (!ModelState.IsValid) 
    { 
     model.CategoryList = new SelectList(db.Categories, "ID", "Name"); // add this 
     return View(model); 
    } 
    // Save and redirect 
} 

Per spiegare il funzionamento interno (il codice sorgente può essere seen here)

Ogni sovraccarico DropDownList() e DropDownListFor() chiama infine il seguente metodo

private static MvcHtmlString SelectInternal(this HtmlHelper htmlHelper, ModelMetadata metadata, 
    string optionLabel, string name, IEnumerable<SelectListItem> selectList, bool allowMultiple, 
    IDictionary<string, object> htmlAttributes) 

che verifica se il selectList (la seconda parametro di @Html.DropDownListFor()) è null

// If we got a null selectList, try to use ViewData to get the list of items. 
if (selectList == null) 
{ 
    selectList = htmlHelper.GetSelectData(name); 
    usedViewData = true; 
} 

che a sua volta richiama

private static IEnumerable<SelectListItem> GetSelectData(this HtmlHelper htmlHelper, string name) 

che valuta il primo parametro di @Html.DropDownListFor() (in questo caso CategoryID)

.... 
o = htmlHelper.ViewData.Eval(name); 
.... 
IEnumerable<SelectListItem> selectList = o as IEnumerable<SelectListItem>; 
if (selectList == null) 
{ 
    throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, 
     MvcResources.HtmlHelper_WrongSelectDataType, 
     name, o.GetType().FullName, "IEnumerable<SelectListItem>")); 
} 

Poiché struttura CategoryID è typeof int, non può essere lanciato a IEnumerable<SelectListItem> e viene generata l'eccezione (che è definita nel file MvcResources.resx come)

<data name="HtmlHelper_WrongSelectDataType" xml:space="preserve"> 
    <value>The ViewData item that has the key '{0}' is of type '{1}' but must be of type '{2}'.</value> 
</data> 
+6

@Shyju, Sì, ho chiesto e risposto (come wiki della comunità) puramente ai fini del dupe-hammering molte altre domande simili su SO che rimangono senza risposta o non accettate. Ma vedo che gli elettori della vendetta sono già iniziati - il primo era meno di 2 secondi dopo la pubblicazione - non abbastanza tempo per leggerlo, figuriamoci la risposta. –

+1

Capisco. Ci sono centinaia di domande con lo stesso problema. Di solito le persone che fanno quelle domande non fanno ricerche appropriate (o hanno copiato e incollato una risposta esistente parola per parola, ma non hanno funzionato!) Quindi non sono sicuro che questo potrebbe davvero aiutare. :) Ben scritto BTW. – Shyju

+0

@Stephen questo non è il modo giusto in cui stai chiedendo e stai rispondendo – Dilip

Problemi correlati