c# - linq mvc
MVC y Entity Framework Html.DisplayNameFor con Composite ViewModel (2)
Estoy bastante cómodo con MVVM usando WPF / Silverlight pero este es mi primer intento de una aplicación web de MVC ... solo un fyi para mi experiencia.
He creado un controlador llamado TestSitesController que se generó automáticamente a partir de la clase de modelo "Sitio" en mi Entity Framework Model (la plantilla que genera las acciones y vistas de lectura / escritura). Lo único que modifiqué fue en 3 puntos, había un parámetro predeterminado de Guid id = null para algunos métodos. Acabo de deshacerme de "= null", todo funciona bien. Aquí hay un ejemplo de lo que he cambiado.
public ActionResult Delete(Guid id = null)
{
//....
}
Esto fue cambiado a
public ActionResult Delete(Guid id)
{
//....
}
El modelo del sitio no es nada especial SiteId, Abreviación y DisplayName ... tratando de mantenerlo lo más simple posible para esta pregunta. Ok, ejecuto el sitio web y voy a htpp: //.../TestSites/ y todo funciona perfectamente.
Noté que todas mis vistas (Crear, Eliminar, Detalles y Editar) están usando un @model MVCWeb.MyEntities.Site con el que estoy perfectamente bien por ahora; pero en la vista Index.cshtml noté que estaba usando una
@model IEnumerable<MVCWeb.MyEntities.Site>
Esto funciona bien para la plantilla generada, pero me gustaría usar un "Modelo de Vista Compuesta" y tal vez es aquí donde estoy tratando de mezclar mi conocimiento de MVVM, pero me quedaría con eso si es posible. En mi opinión, un modelo de vista compuesto es solo un modelo que es específico para una vista que se compone de 1 o más modelos de entidad junto con propiedades adicionales como SelectedSiteId, etc.
Así que creé un ViewModel muy simple llamado TestSitesViewModel
public class TestSitesViewModel
{
//Eventually this will be added to a base ViewModel to get rid
//of the ViewBag dependencies
[Display(Name = "Web Page Title")]
public string WebPageTitle;
public IEnumerable<MVCWeb.MyEntities.Site> Sites;
//Other Entities, IEnumberables, or properties go here
//Not important for this example
}
Luego, en mi controlador, agregué un método de acción llamado IndexWithViewModel
public ActionResult IndexWithViewModel()
{
var vm = new TestSitesViewModel();
vm.WebPageTitle = "Sites With Composite View Model";
vm.Sites = db.Sites.ToList();
return View(vm);
}
Luego hice una copia del Index.cshtml y lo nombré IndexWithModel.cshtml para que coincida con mi nuevo nombre del método ActionResult. Cambié la línea superior de
@model IEnumerable<MVCWeb.MyEntities.Site>
A
@model MVCWeb.Models.TestSitesViewModel
Agregué esto antes de la sección de la tabla para probar el DisplayNameFor y el DisplayFor
@Html.DisplayNameFor(model => model.WebPageTitle)
@Html.DisplayFor(model => model.WebPageTitle)
<br />
Cambiado el
@foreach (var item in Model) {
A
@foreach (var item in Model.Sites) {
Y comentó la sección tr que contiene todos los encabezados de tabla por ahora. Todo funciona a la perfección, excepto que @ Html.DisplayNameFor muestra el nombre de la variable "WebPageTitle" en lugar de usar "Título de página web" como se indica en el atributo Mostrar de la anotación de datos en
[Display(Name = "Web Page Title")]
public string WebPageTitle;
También si comento en la sección tr que contiene la información del encabezado de la tabla. Por mi vida, no puedo averiguar qué poner en. He intentado model.Sites.Abreviation, model.Sites [0] .Abreviation, y varias otras combinaciones, pero obtuve errores.
<tr>
<th>
@Html.DisplayNameFor(model => model.Abbreviation)
</th>
<th>
@Html.DisplayNameFor(model => model.DisplayName)
</th>
<th></th>
</tr>
Entonces, ¿qué debo usar allí? No estoy muy seguro de por qué model.Sites.Abbreviation no funciona ya que Sites es exactamente el mismo tipo que se usó como modelo en el Index.cshtml original
Finalmente me di cuenta de esto después de perder el tiempo por varias horas.
1er problema para poder usar el menú Mostrar en los Anotaciones de datos, métodos para obtener y establecer un asesor, deben agregarse incluso si son solo los predeterminados. Supongo que esto se debe a que solo deben trabajar en propiedades y no en miembros de datos públicos de una clase. Aquí está el código para obtener el
@Html.DisplayNameFor(model => model.WebPageTitle)
para trabajar correctamente
public class TestSitesViewModel
{
//Eventually this will be added to a base ViewModel to get rid of
//the ViewBag dependencies
[Display(Name = "Web Page Title")]
public string WebPageTitle { get; set; }
//PUBLIC DATA MEMBER WON''T WORK
//IT NEEDS TO BE PROPERTY AS DECLARED ABOVE
//public string WebPageTitle;
public IEnumerable<MVCWeb.MyEntities.Site> Sites;
//Other Entities, IEnumberables, or properties go here
//Not important for this example
}
La segunda parte del problema fue acceder a los metadatos en una variable IEnumerable. Declaré una variable temporal llamada headerMetadata y la usé en lugar de intentar acceder a las propiedades a través de IEnumerable
@{var headerMetadata = Model.Sites.FirstOrDefault();}
<tr>
<th>
@Html.DisplayNameFor(model => headerMetadata.Abbreviation)
</th>
<th>
@Html.DisplayNameFor(model => headerMetadata.DisplayName)
</th>
...
Esto plantea la pregunta de ¿cuándo sale la variable headerMetadata fuera del alcance? ¿Está disponible para toda la vista o está limitado a las etiquetas de tabla html? Supongo que esa es otra pregunta para otra cita.
Voy a probar mi experiencia MVC ASP.NET MVC recién aprendida.
En lugar de llamar a @Html.DisplayNameFor(model => model.WebPageTitle)
, intente usar @Html.DisplayFor(model => model.WebPageTitle)
. Parece que estás configurando el valor de WebPageTitle en tu controlador IndexWithViewModel que debería aparecer en tu vista.
Busque templates compartidas para ASP.NET MVC. Puede configurar plantillas personalizadas o parciales para los ayudantes DisplayFor / EditorFor en /Views/Shared/EditorTemplates/Site.cshtml
y /Views/Shared/DisplayTemplates/Site.cshtml
. ASP.NET MVC seleccionará automáticamente esas plantillas al representar su objeto de sitio con DisplayFor y EditorFor.
¡Buena suerte!