El elemento ViewData que tiene la clave 'XXX' es de tipo 'System.Int32' pero debe ser de tipo 'IEnumerable<SelectListItem>'
Tengo el siguiente modelo de vista.
public class ProjectVM
{
....
[Display(Name = "Category")]
[Required(ErrorMessage = "Please select a category")]
public int CategoryID { get; set; }
public IEnumerable<SelectListItem> CategoryList { get; set; }
....
}
y el siguiente método de controlador para crear un nuevo proyecto y asignar unCategory
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
}
y en la 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 se muestra correctamente pero al enviar el formulario, aparece el siguiente mensaje de error
InvalidOperationException: el elemento ViewData que tiene la clave 'CategoryID' es del tipo 'System.Int32' pero debe ser del tipo 'IEnumerable<SelectListItem>'.
El mismo error ocurre usando el @Html.DropDownList()
método, y si paso SelectList usando a ViewBag
o ViewData
.
El error significa que el valor de CategoryList
es nulo (y como resultado, el DropDownListFor()
método espera que el primer parámetro sea de tipo IEnumerable<SelectListItem>
).
No está generando una entrada para cada propiedad de cada SelectListItem
uno CategoryList
(y tampoco debería hacerlo), por lo que no se SelectList
publican valores para el método del controlador y, por lo tanto, el valor de model.CategoryList
en el método POST es null
. Si devuelve la vista, primero debe reasignar el valor de CategoryList
, tal como lo hizo en el método 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
}
Para explicar el funcionamiento interno (el código fuente se puede ver aquí )
Cada sobrecarga de DropDownList()
y DropDownListFor()
eventualmente llama al siguiente método
private static MvcHtmlString SelectInternal(this HtmlHelper htmlHelper, ModelMetadata metadata,
string optionLabel, string name, IEnumerable<SelectListItem> selectList, bool allowMultiple,
IDictionary<string, object> htmlAttributes)
que comprueba si el selectList
(el segundo parámetro de @Html.DropDownListFor()
) esnull
// 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;
}
que a su vez llama
private static IEnumerable<SelectListItem> GetSelectData(this HtmlHelper htmlHelper, string name)
que evalúa el primer parámetro de @Html.DropDownListFor()
(en este 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>"));
}
Debido a que la propiedad CategoryID
es typeof int
, no se puede convertir IEnumerable<SelectListItem>
y se genera la excepción (que se define en el MvcResources.resx
archivo como)
<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>
Según la respuesta de Stephens (user3559349) , esto puede ser útil:
@Html.DropDownListFor(m => m.CategoryID, Model.CategoryList ?? new List<SelectListItem>(), "-Please select-")
o en ProyectoVM:
public class ProjectVM
{
public ProjectVM()
{
CategoryList = new List<SelectListItem>();
}
...
}
Lo más probable es que haya causado algún tipo de error al redirigir a su página y no haya inicializado las listas desplegables de su modelo nuevamente.
Asegúrese de inicializar sus menús desplegables en el constructor del modelo o cada vez antes de enviar dicho modelo a la página.
De lo contrario, deberá mantener el estado de las listas desplegables a través de la bolsa de visualización o mediante los ayudantes de valores ocultos.