Was ich sehe, ist eine Zeichenfolge-Layout-Eigenschaft. Aber wie kann ich ein Modell explizit an das Layout übergeben?
Scheint, als hätten Sie Ihre Viewmodels etwas falsch modelliert, wenn Sie dieses Problem haben.
Persönlich würde ich niemals eine Layoutseite eingeben. Wenn Sie dies tun möchten, sollten Sie über ein Basis-Ansichtsmodell verfügen, das von den anderen Ansichtsmodellen übernommen wird, und Sie geben Ihr Layout in das Basis-Ansichtsmodell ein, und Sie wechseln einmalig zu dem jeweiligen Modell.
Beispiel: Controller:
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;
}
}
Beispiel oben auf der Layoutseite
@{
var viewModel = (MainLayoutViewModel)ViewBag.MainLayoutViewModel;
}
Jetzt können Sie die Variable 'viewModel' in Ihrer Layoutseite mit vollem Zugriff auf das typisierte Objekt referenzieren.
Dieser Ansatz gefällt mir, weil der Controller das Layout steuert, während die einzelnen Seitenansichtsmodelle layoutunabhängig bleiben.
Hinweise zum MVC Core
IActionFilter
und die gleiche Arbeit in OnActionExecuting
. Setzen Sie MyActionFilter
auf Ihre 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;
}
}
}
dies ist ziemlich einfach. Alles, was Sie tun müssen, ist ein Basis-Ansichtsmodell zu erstellen und sicherzustellen, dass ALLES! und ich meine ALLES! Ihrer Ansichten, die dieses Layout jemals verwenden werden, erhalten Ansichten, die dieses Basismodell verwenden!
public class SomeViewModel : ViewModelBase
{
public bool ImNotEmpty = true;
}
public class EmptyViewModel : ViewModelBase
{
}
public abstract class ViewModelBase
{
}
in der _Layout.cshtml:
@model Models.ViewModelBase
<!DOCTYPE html>
<html>
and so on...
in der Index-Methode (zum Beispiel) im Home-Controller:
public ActionResult Index()
{
var model = new SomeViewModel()
{
};
return View(model);
}
die Index.cshtml:
@model Models.SomeViewModel
@{
ViewBag.Title = "Title";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="row">
ich stimme nicht zu, dass die Übergabe eines Modells an _layout ein Fehler ist, dass einige Benutzerinformationen übergeben werden können und die Daten in der Vererbungskette der Controller aufgefüllt werden können, sodass nur eine Implementierung erforderlich ist.
für fortgeschrittene Zwecke sollten Sie in Betracht ziehen, mithilfe von Injection einen benutzerdefinierten statischen Inhalt zu erstellen, und diesen Modellnamespace in die _Layout.cshtml einschließen.
aber für grundlegende Benutzer ist dies der Trick
Warum fügen Sie nicht einfach eine neue Teilansicht hinzu, indem der spezifische Controller von i das erforderliche Modell an die Teilansicht übergibt und schließlich die erwähnte Teilansicht in Ihrer Layout.cshtml mit RenderPartial oder RenderAction rendert?
Ich verwende diese Methode, um die Informationen des angemeldeten Benutzers wie Name, Profilbild usw. anzuzeigen.
Eine gängige Lösung besteht darin, ein Basisansichtsmodell zu erstellen, das die in der Layoutdatei verwendeten Eigenschaften enthält, und dann vom Basismodell zu den auf den jeweiligen Seiten verwendeten Modellen zu erben.
Das Problem bei diesem Ansatz ist, dass Sie sich jetzt in das Problem eines Modells eingeschlossen haben, das nur von einer anderen Klasse erben kann, und Ihre Lösung ist möglicherweise so, dass Sie die Vererbung für das von Ihnen beabsichtigte Modell nicht verwenden können.
Meine Lösung beginnt auch mit einem Basisansicht-Modell:
public class LayoutModel
{
public LayoutModel(string title)
{
Title = title;
}
public string Title { get;}
}
Was ich dann verwende, ist eine generische Version des LayoutModels, die vom LayoutModel wie folgt erbt:
public class LayoutModel<T> : LayoutModel
{
public LayoutModel(T pageModel, string title) : base(title)
{
PageModel = pageModel;
}
public T PageModel { get; }
}
Mit dieser Lösung habe ich die Notwendigkeit der Vererbung zwischen dem Layoutmodell und dem Modell getrennt.
Nun kann ich also das LayoutModel in Layout.cshtml folgendermaßen verwenden:
@model LayoutModel
<!doctype html>
<html>
<head>
<title>@Model.Title</title>
</head>
<body>
@RenderBody()
</body>
</html>
Und auf einer Seite können Sie das generische LayoutModel wie folgt verwenden:
@model LayoutModel<Customer>
@{
var customer = Model.PageModel;
}
<p>Customer name: @customer.Name</p>
Von Ihrem Controller geben Sie einfach ein Modell vom Typ LayoutModel zurück:
public ActionResult Page()
{
return View(new LayoutModel<Customer>(new Customer() { Name = "Test" }, "Title");
}
Vielleicht ist es technisch nicht die richtige Art, damit umzugehen, aber die einfachste und vernünftigste Lösung für mich ist, einfach eine Klasse zu erstellen und sie im Layout zu instanziieren. Es ist eine einmalige Ausnahme von der ansonsten korrekten Vorgehensweise. Wenn dies mehr als im Layout gemacht wird, müssen Sie Ihre Aktivitäten ernsthaft überdenken und vielleicht ein paar weitere Tutorials lesen, bevor Sie in Ihrem Projekt weiterarbeiten.
public class MyLayoutModel {
public User CurrentUser {
get {
.. get the current user ..
}
}
}
dann in der Ansicht
@{
// Or get if from your DI container
var myLayoutModel = new MyLayoutModel();
}
in .net Core können Sie dies sogar überspringen und die Abhängigkeitsprüfung verwenden.
@inject My.Namespace.IMyLayoutModel myLayoutModel
Es ist einer dieser Bereiche, die irgendwie schattig sind. Aber angesichts der extrem komplizierten Alternativen, die ich hier sehe, ist es meiner Meinung nach mehr als eine gute Ausnahme, im Namen der Praktikabilität zu sein. Vor allem, wenn Sie darauf achten, dass es einfach bleibt, und sicherstellen, dass schwere Logik (ich würde behaupten, dass es wirklich keine geben sollte, die Anforderungen sich jedoch unterscheiden) in einer anderen Klasse/Schicht liegt, zu der sie gehört. Es ist sicherlich besser, ALLE Ihrer Controller oder Modelle zu verschmutzen, um im Grunde nur eine Ansicht zu erhalten.
alte Frage, nur um die Lösung für MVC5-Entwickler zu erwähnen, können Sie die Model
-Eigenschaft genauso wie in view verwenden.
Die Model
-Eigenschaft in Ansicht und Layout ist mit demselben ViewDataDictionary
-Objekt verknüpft. Sie müssen also keine zusätzlichen Arbeiten ausführen, um Ihr Modell an die Layoutseite zu übergeben, und Sie müssen @model MyModelName
nicht im Layout angeben.
Beachten Sie jedoch, dass bei Verwendung von @Model.XXX
im Layout das intelliSense-Kontextmenü nicht angezeigt wird, da die Model
hier ein dynamisches Objekt ist, genau wie ViewBag
.
Nehmen wir an, Ihr Modell besteht aus einer Sammlung von Objekten (oder möglicherweise einem einzelnen Objekt). Für jedes Objekt im Modell gehen Sie wie folgt vor.
1) Legen Sie das Objekt, das Sie anzeigen möchten, in das ViewBag ein. Zum Beispiel:
ViewBag.YourObject = yourObject;
2) Fügen Sie am Anfang von _Layout.cshtml eine using-Anweisung hinzu, die die Klassendefinition für Ihre Objekte enthält. Zum Beispiel:
@ using YourApplication.YourClasses;
3) Wenn Sie Ihr Objekt in _Layout referenzieren, wenden Sie es an. Sie können die Besetzung aufgrund dessen, was Sie in (2) gemacht haben, anwenden.