Lo que veo es una propiedad de diseño de cadena. Pero, ¿cómo puedo pasar un modelo al diseño de forma explícita?
Modelestá disponible en _Layout. Estoy usando MVC5.
Lo que veo es una propiedad de diseño de cadena. Pero, ¿cómo puedo pasar un modelo al diseño de forma explícita?
Modelestá disponible en _Layout. Estoy usando MVC5.
Respuestas:
Parece que ha modelado sus modelos de vista un poco mal si tiene este problema.
Personalmente, nunca escribiría una página de diseño. Pero si desea hacer eso, debe tener un modelo de vista base que hereden sus otros modelos de vista y escribir su diseño en el modelo de vista base y sus páginas en el modelo de vista específico una vez.
Ejemplo: controlador:
public class MyController : Controller
{
public MainLayoutViewModel MainLayoutViewModel { get; set; }
public MyController()
{
this.MainLayoutViewModel = new MainLayoutViewModel();//has property PageTitle
this.MainLayoutViewModel.PageTitle = "my title";
this.ViewData["MainLayoutViewModel"] = this.MainLayoutViewModel;
}
}
Ejemplo de parte superior de la página de diseño
@{
var viewModel = (MainLayoutViewModel)ViewBag.MainLayoutViewModel;
}
Ahora puede hacer referencia a la variable 'viewModel' en su página de diseño con acceso completo al objeto escrito.
Me gusta este enfoque porque es el controlador el que controla el diseño, mientras que los modelos de vista de página individuales siguen siendo independientes del diseño.
Notas para MVC Core
IActionFiltery hacer exactamente el mismo trabajo en OnActionExecuting. Ponte MyActionFiltertu MyController.
public class MyActionFilter: Attribute, IActionFilter
{
public void OnActionExecuted(ActionExecutedContext context)
{
}
public void OnActionExecuting(ActionExecutingContext context)
{
var myController= context.Controller as MyController;
if (myController!= null)
{
myController.Layout = new MainLayoutViewModel
{
};
myController.ViewBag.MainLayoutViewModel= myController.Layout;
}
}
}
esto es algo bastante básico, todo lo que necesita hacer es crear un modelo de vista base y asegurarse de que TODO! y me refiero a TODOS! de sus vistas que alguna vez usarán ese diseño, recibirán vistas que usen ese modelo base.
public class SomeViewModel : ViewModelBase
{
public bool ImNotEmpty = true;
}
public class EmptyViewModel : ViewModelBase
{
}
public abstract class ViewModelBase
{
}
en _Layout.cshtml:
@model Models.ViewModelBase
<!DOCTYPE html>
<html>
and so on...
en el método Index (por ejemplo) en el controlador doméstico:
public ActionResult Index()
{
var model = new SomeViewModel()
{
};
return View(model);
}
el Index.cshtml:
@model Models.SomeViewModel
@{
ViewBag.Title = "Title";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="row">
No estoy de acuerdo con que pasar un modelo al _layout sea un error, se puede pasar alguna información del usuario y los datos se pueden completar en la cadena de herencia de los controladores, por lo que solo se necesita una implementación.
obviamente, para un propósito más avanzado, debería considerar crear un contacto estático personalizado mediante inyección e incluir ese espacio de nombres de modelo en _Layout.cshtml.
pero para usuarios básicos esto servirá
Una solución común es crear un modelo de vista base que contenga las propiedades utilizadas en el archivo de diseño y luego heredar del modelo base a los modelos utilizados en las páginas respectivas.
El problema con este enfoque es que ahora se ha encerrado en el problema de que un modelo solo puede heredar de otra clase, y tal vez su solución sea tal que no pueda usar la herencia en el modelo que pretendía de todos modos.
Mi solución también comienza con un modelo de vista base:
public class LayoutModel
{
public LayoutModel(string title)
{
Title = title;
}
public string Title { get;}
}
Lo que luego uso es una versión genérica de LayoutModel que hereda de LayoutModel, así:
public class LayoutModel<T> : LayoutModel
{
public LayoutModel(T pageModel, string title) : base(title)
{
PageModel = pageModel;
}
public T PageModel { get; }
}
Con esta solución he desconectado la necesidad de tener herencia entre el modelo de diseño y el modelo.
Entonces ahora puedo seguir adelante y usar LayoutModel en Layout.cshtml de esta manera:
@model LayoutModel
<!doctype html>
<html>
<head>
<title>@Model.Title</title>
</head>
<body>
@RenderBody()
</body>
</html>
Y en una página puede usar el LayoutModel genérico como este:
@model LayoutModel<Customer>
@{
var customer = Model.PageModel;
}
<p>Customer name: @customer.Name</p>
Desde su controlador, simplemente devuelve un modelo de tipo LayoutModel:
public ActionResult Page()
{
return View(new LayoutModel<Customer>(new Customer() { Name = "Test" }, "Title");
}
¿Por qué no agrega una nueva vista parcial con el controlador específico de i pasando el modelo requerido a la vista parcial y finalmente renderiza la vista parcial mencionada en su Layout.cshtml usando RenderPartial o RenderAction?
Utilizo este método para mostrar la información del usuario que ha iniciado sesión, como el nombre, la imagen de perfil, etc.
Pregunta anterior, pero solo para mencionar la solución para los desarrolladores de MVC5, puede usar la Modelpropiedad igual que en la vista.
La Modelpropiedad tanto en la vista como en el diseño está asociada con el mismo ViewDataDictionaryobjeto, por lo que no tiene que hacer ningún trabajo adicional para pasar su modelo a la página de diseño, y no tiene que declarar @model MyModelNameen el diseño.
Pero tenga @Model.XXXen cuenta que cuando use en el diseño, el menú contextual de intelliSense no aparecerá porque Modelaquí hay un objeto dinámico como ViewBag.
Tal vez técnicamente no sea la forma correcta de manejarlo, pero la solución más simple y razonable para mí es simplemente crear una clase e instanciarla en el diseño. Es una excepción única a la forma correcta de hacerlo. Si esto se hace más que en el diseño, entonces debe reconsiderar seriamente lo que está haciendo y tal vez leer algunos tutoriales más antes de avanzar más en su proyecto.
public class MyLayoutModel {
public User CurrentUser {
get {
.. get the current user ..
}
}
}
entonces en la vista
@{
// Or get if from your DI container
var myLayoutModel = new MyLayoutModel();
}
en .net core, incluso puede omitir eso y usar la inyección de dependencia.
@inject My.Namespace.IMyLayoutModel myLayoutModel
Es una de esas áreas que tiene cierta sombra. Pero dadas las alternativas extremadamente complicadas que estoy viendo aquí, creo que es más que una buena excepción para hacer en nombre de la practicidad. Especialmente si se asegura de mantenerlo simple y se asegura de que cualquier lógica pesada (yo diría que realmente no debería haber ninguna, pero los requisitos difieren) está en otra clase / capa a la que pertenece. Ciertamente es mejor que contaminar TODOS sus controladores o modelos por el simple hecho de tener una sola vista.
Hay otra forma de archivarlo.
Simplemente implemente la clase BaseController para todos los controladores .
En la BaseControllerclase, cree un método que devuelva una clase Modelo como, por ejemplo.
public MenuPageModel GetTopMenu() { var m = new MenuPageModel(); // populate your model here return m; }
Layoutpágina puedes llamar a ese métodoGetTopMenu()@using GJob.Controllers <header class="header-wrapper border-bottom border-secondary"> <div class="sticky-header" id="appTopMenu"> @{ var menuPageModel = ((BaseController)this.ViewContext.Controller).GetTopMenu(); } @Html.Partial("_TopMainMenu", menuPageModel) </div> </header>
Supongamos que su modelo es una colección de objetos (o tal vez un solo objeto). Para cada objeto del modelo, haga lo siguiente.
1) Coloque el objeto que desea mostrar en ViewBag. Por ejemplo:
ViewBag.YourObject = yourObject;
2) Agregue una declaración using en la parte superior de _Layout.cshtml que contiene la definición de clase para sus objetos. Por ejemplo:
@using YourApplication.YourClasses;
3) Cuando haga referencia a yourObject en _Layout, cámbielo. Puede aplicar el yeso por lo que hizo en (2).
public interface IContainsMyModel
{
ViewModel Model { get; }
}
public class ViewModel : IContainsMyModel
{
public string MyProperty { set; get; }
public ViewModel Model { get { return this; } }
}
public class Composition : IContainsMyModel
{
public ViewModel ViewModel { get; set; }
}
Utilice IContainsMyModel en su diseño.
Resuelto. Regla de interfaces.
Por ejemplo
@model IList<Model.User>
@{
Layout="~/Views/Shared/SiteLayout.cshtml";
}
Leer más sobre la nueva directiva @model