Ce que je vois est une propriété de mise en page de chaîne. Mais comment puis-je passer un modèle à la mise en page explicitement?
Model
est disponible en _Layout
. J'utilise MVC5.
Ce que je vois est une propriété de mise en page de chaîne. Mais comment puis-je passer un modèle à la mise en page explicitement?
Model
est disponible en _Layout
. J'utilise MVC5.
Réponses:
Il semble que vous ayez un peu mal modélisé vos modèles de vue si vous rencontrez 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 tapez votre mise en page dans le modèle de vue de base et vous pages vers le modèle spécifique une fois.
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 maintenant référencer la variable 'viewModel' dans votre page de mise en page avec un accès complet à l'objet tapé.
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 de page individuels restent indépendants de la mise en page.
Notes pour MVC Core
IActionFilter
et de faire exactement le même travail dans OnActionExecuting
. Mettez MyActionFilter
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;
}
}
}
ce sont des 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 TOUT! et je veux dire TOUT! 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 _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 pour dire que passer un modèle à _layout est une erreur, certaines informations utilisateur peuvent être transmises et les données peuvent être renseignées dans la chaîne d'héritage des contrôleurs, de sorte qu'une seule implémentation est nécessaire.
évidemment, pour des raisons plus avancées, vous devriez envisager de créer un contaxt statique personnalisé à l'aide de l'injection et d'inclure cet espace de noms de modèle dans le _Layout.cshtml.
mais pour les utilisateurs basiques, cela fera l'affaire
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 aux modèles utilisés sur les pages respectives.
Le problème avec cette approche est que vous vous êtes maintenant enfermé dans le problème d'un modèle qui ne peut hériter que d'une 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;}
}
Ce que j'utilise ensuite est 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 déconnecté la nécessité d'avoir un héritage entre le modèle de disposition et le modèle.
Alors maintenant, je peux continuer et 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 LayoutModel générique comme ceci:
@model LayoutModel<Customer>
@{
var customer = Model.PageModel;
}
<p>Customer name: @customer.Name</p>
Depuis votre contrôleur, vous renvoyez simplement un modèle de type LayoutModel:
public ActionResult Page()
{
return View(new LayoutModel<Customer>(new Customer() { Name = "Test" }, "Title");
}
Pourquoi ne pas simplement ajouter une nouvelle vue partielle avec le contrôleur spécifique de i en passant le modèle requis à la vue partielle et enfin 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é telles que le nom, la photo de profil, etc.
ancienne question mais juste pour mentionner la solution pour les développeurs MVC5, vous pouvez utiliser la Model
même propriété que dans la vue.
La Model
propriété dans la vue et la mise en page est associée au même ViewDataDictionary
objet, vous n'avez donc pas à faire de travail supplémentaire pour transmettre votre modèle à la page de mise en page, et vous n'avez pas à déclarer @model MyModelName
dans la mise en page.
Mais notez que lorsque vous utilisez @Model.XXX
dans la mise en page, le menu contextuel intelliSense n'apparaîtra pas car Model
ici est un objet dynamique comme ViewBag
.
Ce n'est peut-être pas techniquement la bonne façon de le gérer, mais la solution la plus simple et la plus raisonnable pour moi est simplement de créer une classe et de l'instancier dans la mise en page. C'est une exception ponctuelle à la manière par ailleurs correcte de procéder. Si cela est fait plus que dans la mise en page, vous devez repenser sérieusement ce que vous faites et peut-être lire quelques tutoriels supplémentaires avant de progresser dans votre projet.
public class MyLayoutModel {
public User CurrentUser {
get {
.. get the current user ..
}
}
}
puis dans la vue
@{
// Or get if from your DI container
var myLayoutModel = new MyLayoutModel();
}
dans .net core, vous pouvez même ignorer cela et utiliser l'injection de dépendances.
@inject My.Namespace.IMyLayoutModel myLayoutModel
C'est l'un de ces domaines qui est un peu ombragé. Mais étant donné les alternatives extrêmement compliquées que je vois ici, je pense que c'est plus qu'une bonne exception à faire au nom de l'aspect pratique. Surtout si vous vous assurez de garder les choses simples et de vous assurer que toute logique lourde (je dirais qu'il ne devrait vraiment pas y en avoir, mais les exigences diffèrent) se trouve dans une autre classe / couche à laquelle elle appartient. C'est certainement mieux que de polluer TOUS vos contrôleurs ou modèles pour une seule vue.
Il existe une autre façon de l'archiver.
Il suffit de mettre en œuvre la classe BaseController pour tous les contrôleurs .
Dans la BaseController
classe, créez une méthode qui renvoie une classe Model comme par exemple.
public MenuPageModel GetTopMenu() { var m = new MenuPageModel(); // populate your model here return m; }
Layout
page, vous pouvez appeler cette méthodeGetTopMenu()
@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>
Supposons que votre modèle soit une collection d'objets (ou peut-être un seul objet). Pour chaque objet du modèle, procédez comme suit.
1) Placez l'objet que vous souhaitez afficher dans le ViewBag. Par exemple:
ViewBag.YourObject = yourObject;
2) Ajoutez une instruction using en haut de _Layout.cshtml qui contient la définition de classe pour vos objets. Par exemple:
@utilisation de YourApplication.YourClasses;
3) Lorsque vous référencez votreObjet dans _Layout, lancez-le. Vous pouvez appliquer la distribution en fonction de ce que vous avez fait dans (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; }
}
Utilisez IContainsMyModel dans votre mise en page.
Résolu. Règle des interfaces.
Par exemple
@model IList<Model.User>
@{
Layout="~/Views/Shared/SiteLayout.cshtml";
}
En savoir plus sur la nouvelle directive @model