Ce que je vois, c'est une propriété de disposition de chaîne. Mais comment puis-je passer explicitement un modèle à la propriété Layout ?
Réponses
Trop de publicités?- Ajoutez une propriété à votre contrôleur (ou contrôleur de base) appelée MainLayoutViewModel (ou autre) avec le type que vous souhaitez utiliser.
- Dans le constructeur de votre contrôleur (ou contrôleur de base), instanciez le type et attribuez-lui la propriété.
- Le placer dans le champ ViewData (ou ViewBag)
- Dans la page de présentation, associez cette propriété à votre type.
Exemple : Contrôleur :
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;
}
}
Exemple de haut de page de mise en page
@{
var viewModel = (MainLayoutViewModel)ViewBag.MainLayoutViewModel;
}
Vous pouvez désormais faire référence à la variable "viewModel" dans votre page de présentation en bénéficiant d'un accès complet à l'objet typé.
J'aime cette approche parce que c'est le contrôleur qui contrôle la mise en page, tandis que les modèles de vue des pages individuelles restent indépendants de la mise en page.
Notes pour MVC Core
Mvc Core semble effacer le contenu de ViewData/ViewBag lors du premier appel de chaque action. Cela signifie que l'assignation de ViewData dans le constructeur ne fonctionne pas. Ce qui fonctionne, en revanche, c'est l'utilisation d'un IActionFilter
et faire exactement le même travail en OnActionExecuting
. Mettre MyActionFilter
sur votre 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;
}
}
}
Il semble que vous ayez mal modélisé vos modèles de vue si vous avez ce problème.
Personnellement, je ne taperais jamais une page de mise en page. Mais si vous voulez faire cela, vous devriez avoir un modèle de vue de base dont vos autres modèles de vue héritent et taper votre présentation dans le modèle de vue de base et vos pages dans le modèle spécifique une fois.
Une solution courante consiste à créer un modèle de vue de base qui contient les propriétés utilisées dans le fichier de mise en page, puis à hériter du modèle de base pour les modèles utilisés sur les pages respectives.
Le problème avec cette approche est que vous vous êtes enfermé dans le problème d'un modèle qui ne peut hériter que d'une seule autre classe, et peut-être que votre solution est telle que vous ne pouvez pas utiliser l'héritage sur le modèle que vous vouliez de toute façon.
Ma solution commence également par un modèle de vue de base :
public class LayoutModel
{
public LayoutModel(string title)
{
Title = title;
}
public string Title { get;}
}
J'utilise alors une version générique du LayoutModel qui hérite du LayoutModel, comme ceci :
public class LayoutModel<T> : LayoutModel
{
public LayoutModel(T pageModel, string title) : base(title)
{
PageModel = pageModel;
}
public T PageModel { get; }
}
Avec cette solution, j'ai supprimé la nécessité d'avoir un héritage entre le modèle de mise en page et le modèle.
Je peux maintenant utiliser le LayoutModel dans Layout.cshtml comme ceci :
@model LayoutModel
<!doctype html>
<html>
<head>
<title>@Model.Title</title>
</head>
<body>
@RenderBody()
</body>
</html>
Et sur une page, vous pouvez utiliser le modèle générique LayoutModel comme ceci :
@model LayoutModel<Customer>
@{
var customer = Model.PageModel;
}
<p>Customer name: @customer.Name</p>
Le contrôleur renvoie simplement un modèle de type LayoutModel :
public ActionResult Page()
{
return View(new LayoutModel<Customer>(new Customer() { Name = "Test" }, "Title");
}
Il s'agit de choses assez basiques, tout ce que vous avez à faire est de créer un modèle de vue de base et de vous assurer que TOUTES ! et je dis bien TOUTES ! de vos vues qui utiliseront cette disposition recevront des vues qui utilisent ce modèle de base !
public class SomeViewModel : ViewModelBase
{
public bool ImNotEmpty = true;
}
public class EmptyViewModel : ViewModelBase
{
}
public abstract class ViewModelBase
{
}
dans le fichier _Layout.cshtml :
@model Models.ViewModelBase
<!DOCTYPE html>
<html>
and so on...
dans la méthode Index (par exemple) dans le contrôleur domestique :
public ActionResult Index()
{
var model = new SomeViewModel()
{
};
return View(model);
}
l'Index.cshtml :
@model Models.SomeViewModel
@{
ViewBag.Title = "Title";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="row">
Je ne suis pas d'accord sur le fait que passer un modèle à _layout est une erreur, certaines informations sur l'utilisateur peuvent être passées et les données peuvent être remplies dans la chaîne d'héritage des contrôleurs, de sorte qu'une seule implémentation est nécessaire.
Il est évident que pour des objectifs plus avancés, vous devriez envisager de créer un contenu statique personnalisé en utilisant l'injection et d'inclure l'espace de noms du modèle dans le fichier _Layout.cshtml.
mais pour les utilisateurs de base, ceci fera l'affaire
Pourquoi ne pas ajouter une nouvelle vue partielle avec son propre contrôleur spécifique en passant le modèle requis à la vue partielle et finalement rendre la vue partielle mentionnée sur votre Layout.cshtml en utilisant RenderPartial ou RenderAction ?
J'utilise cette méthode pour afficher les informations de l'utilisateur connecté, comme son nom, sa photo de profil, etc.
- Réponses précédentes
- Plus de réponses