asp.net mvc 3 - net - MVC3-Viewmodel con lista de tipos complejos
www asp net mvc mvc4 (2)
Disculpas si esto ha sido preguntado antes; Hay un millón de maneras de expresarlo, por lo que la búsqueda de una respuesta ha resultado difícil.
Tengo un modelo de vista con las siguientes propiedades:
public class AssignSoftwareLicenseViewModel
{
public int LicenseId { get; set; }
public ICollection<SelectableDeviceViewModel> Devices { get; set; }
}
Una versión simplificada de SelectableDeviceViewModel sería esta:
public class SelectableDeviceViewModel
{
public int DeviceInstanceId { get; set; }
public bool IsSelected { get; set; }
public string Name { get; set; }
}
En mi Vista, estoy intentando mostrar una lista de casillas de verificación editables para la propiedad Dispositivos, dentro de un formulario de entrada. Actualmente, mi vista se ve así:
@using (Html.BeginForm())
{
@Html.HiddenFor(x => Model.LicenseId)
<table>
<tr>
<th>Name</th>
<th></th>
</tr>
@foreach (SelectableDeviceViewModel device in Model.Devices)
{
@Html.HiddenFor(x => device.DeviceInstanceId)
<tr>
<td>@Html.CheckBoxFor(x => device.IsSelected)</td>
<td>@device.Name</td>
</tr>
}
</table>
<input type="submit" value="Assign" />
}
El problema es que, cuando el modelo se vuelve a publicar en el controlador, los dispositivos son nulos.
Mi suposición es que esto está sucediendo porque aunque estoy editando su contenido, la propiedad de Dispositivos nunca se incluye explícitamente en el formulario. Intenté incluirlo con HiddenFor, pero eso solo dio como resultado que el modelo tuviera una lista vacía en lugar de nula.
¿Alguna idea de lo que estoy haciendo mal aquí?
Mi suposición es que esto está sucediendo porque aunque estoy editando su contenido, la propiedad de Dispositivos nunca se incluye explícitamente en el formulario.
No, tu suposición es errónea. La razón por la que esto no se vincula correctamente es porque los campos de entrada no tienen nombres correctos. Por ejemplo, se denominan name="IsSelected"
lugar de name="Devices[0].IsSelected"
. Eche un vistazo al formato de conexión correcto que debe utilizarse para enlazar a las colecciones: http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
¿Pero por qué sucede esto?
Ocurre debido al bucle foreach
que foreach
en tu vista. Usó x => device.IsSelected
como lambda expresión para la casilla de verificación pero esto no tiene en cuenta la propiedad de Dispositivos (como puede ver al mirar el código fuente generado de su página web).
¿Entonces qué debo hacer?
Personalmente, le recomendaría utilizar plantillas de editor, ya que respetan el contexto de navegación de las propiedades complejas y generan nombres de entrada correctos. Deshazte de todo el bucle foreach
en tu vista y reemplázalo con una sola línea de código:
@Html.EditorFor(x => x.Devices)
y ahora defina una plantilla de editor personalizado que ASP.NET MVC representará automáticamente para cada elemento de la colección de Dispositivos. Advertencia: la ubicación y el nombre de esta plantilla son muy importantes ya que esto funciona por convención: ~/Views/Shared/EditorTemplates/SelectableDeviceViewModel.cshtml
:
@model SelectableDeviceViewModel
@Html.HiddenFor(x => x.DeviceInstanceId)
<tr>
<td>@Html.CheckBoxFor(x => x.IsSelected)</td>
<td>@Html.DisplayFor(x => x.Name)</td>
</tr>
Otro enfoque (que no recomiendo) es cambiar su ICollection
actual en su modelo de vista a una colección indexada (como IList<T>
o una matriz T[]
):
public class AssignSoftwareLicenseViewModel
{
public int LicenseId { get; set; }
public IList<SelectableDeviceViewModel> Devices { get; set; }
}
y luego, en lugar de foreach, use un bucle for
:
@for (var i = 0; i < Model.Devices.Count; i++)
{
@Html.HiddenFor(x => x.Devices[i].DeviceInstanceId)
<tr>
<td>@Html.CheckBoxFor(x => x.Devices[i].IsSelected)</td>
<td>@Html.DisplayFor(x => x.Devices[i].Name</td>
</tr>
}
EditorPara que las plantillas funcionen y mantenga limpio el código No necesitas los bucles y el modelo se devuelve correctamente.
Sin embargo, ¿alguien ha tenido problemas con la validación en modelos de vista complejos (Editor anidado para plantillas)? Estoy usando Kendo Validator y me encuentro con todo tipo de errores de jQuery.