Was ich sehe, ist eine String-Layout-Eigenschaft. Aber wie kann ich ein Modell explizit an das Layout übergeben?
Model
ist verfügbar in _Layout
. Ich benutze MVC5.
Was ich sehe, ist eine String-Layout-Eigenschaft. Aber wie kann ich ein Modell explizit an das Layout übergeben?
Model
ist verfügbar in _Layout
. Ich benutze MVC5.
Antworten:
Scheint, als hätten Sie Ihre Ansichtsmodelle etwas falsch modelliert, wenn Sie dieses Problem haben.
Persönlich würde ich niemals eine Layoutseite eingeben. Wenn Sie dies jedoch tun möchten, sollten Sie ein Basisansichtsmodell haben, von dem Ihre anderen Ansichtsmodelle erben, und Ihr Layout in das Basisansichtsmodell eingeben und Ihre Seiten einmal in das spezifische.
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 auf die Variable 'viewModel' auf Ihrer Layoutseite mit vollem Zugriff auf das eingegebene Objekt verweisen.
Ich mag diesen Ansatz, weil es der Controller ist, der das Layout steuert, während die einzelnen Seitenansichtsmodelle layoutunabhängig bleiben.
Hinweise für MVC Core
IActionFilter
und genau die gleiche Arbeit in OnActionExecuting
. Zieh MyActionFilter
deine an 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 grundlegend. Alles, was Sie tun müssen, ist, ein Basisansichtsmodell zu erstellen und sicherzustellen, dass ALLE! und ich meine ALL! Von Ihren Ansichten, die jemals dieses Layout verwenden werden, erhalten Sie 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 bin nicht der Meinung, dass das Übergeben eines Modells an das _layout ein Fehler ist. Einige Benutzerinformationen können übergeben werden und die Daten können in die Vererbungskette des Controllers eingetragen werden, sodass nur eine Implementierung erforderlich ist.
Für fortgeschrittenere Zwecke sollten Sie natürlich in Betracht ziehen, einen benutzerdefinierten statischen Kontraxt mithilfe von Injection zu erstellen und diesen Modell-Namespace in die Datei _Layout.cshtml aufzunehmen.
Aber für einfache Benutzer reicht dies aus
Eine übliche Lösung besteht darin, ein Basisansichtsmodell zu erstellen, das die in der Layoutdatei verwendeten Eigenschaften enthält, und dann vom Basismodell an die auf den jeweiligen Seiten verwendeten Modelle zu erben.
Das Problem bei diesem Ansatz ist, dass Sie sich jetzt auf das Problem eines Modells festgelegt haben, das nur von einer anderen Klasse erben kann, und Ihre Lösung möglicherweise so ist, dass Sie die Vererbung für das von Ihnen beabsichtigte Modell sowieso nicht verwenden können.
Meine Lösung beginnt auch mit einem Basisansichtsmodell:
public class LayoutModel
{
public LayoutModel(string title)
{
Title = title;
}
public string Title { get;}
}
Was ich dann benutze, ist eine generische Version des LayoutModels, die vom LayoutModel erbt, wie folgt:
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 einer Vererbung zwischen dem Layoutmodell und dem Modell getrennt.
Jetzt kann ich 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");
}
Warum fügen Sie nicht einfach eine neue Teilansicht hinzu, wobei i's spezifischer Controller das erforderliche Modell an die Teilansicht übergibt und schließlich die erwähnte Teilansicht in Ihrer Layout.cshtml mit RenderPartial oder RenderAction rendert?
Ich benutze diese Methode, um die angemeldeten Benutzerinformationen wie Name, Profilbild usw. anzuzeigen.
alte Frage, aber nur um die Lösung für MVC5-Entwickler zu erwähnen, können Sie die verwenden Model
Eigenschaft wie in der Ansicht verwenden.
Die Model
Eigenschaft in Ansicht und Layout ist demselben ViewDataDictionary
Objekt zugeordnet, sodass Sie keine zusätzlichen Arbeiten ausführen müssen, um Ihr Modell an die Layoutseite zu übergeben, und Sie müssen nicht @model MyModelName
im Layout deklarieren .
@Model.XXX
Beachten Sie jedoch, dass bei Verwendung im Layout das IntelliSense-Kontextmenü nicht angezeigt wird, da es sich Model
hier um ein dynamisches Objekt handelt ViewBag
.
Vielleicht ist es technisch nicht die richtige Art, damit umzugehen, aber die einfachste und vernünftigste Lösung für mich besteht darin, einfach eine Klasse zu erstellen und sie im Layout zu instanziieren. Dies ist eine einmalige Ausnahme von der ansonsten korrekten Vorgehensweise. Wenn dies mehr als im Layout erfolgt, müssen Sie Ihre Arbeitsweise ernsthaft überdenken und möglicherweise einige weitere Tutorials lesen, bevor Sie mit Ihrem Projekt fortfahren.
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ängigkeitsinjektion verwenden.
@inject My.Namespace.IMyLayoutModel myLayoutModel
Es ist einer dieser Bereiche, der etwas schattig ist. Aber angesichts der extrem komplizierten Alternativen, die ich hier sehe, denke ich, dass es mehr als eine gute Ausnahme ist, im Namen der Praktikabilität zu machen. Besonders wenn Sie sicherstellen, dass es einfach bleibt und dass jede schwere Logik (ich würde argumentieren, dass es eigentlich keine geben sollte, aber die Anforderungen unterschiedlich sind) in einer anderen Klasse / Schicht liegt, zu der sie gehört. Es ist sicherlich besser, als ALLE Ihre Controller oder Modelle zu verschmutzen, um im Grunde nur eine Ansicht zu erhalten.
Es gibt eine andere Möglichkeit, es zu archivieren.
Implementieren Sie einfach die BaseController-Klasse für alle Controller .
BaseController
Erstellen Sie in der Klasse eine Methode, die beispielsweise eine Model-Klasse zurückgibt.
public MenuPageModel GetTopMenu() { var m = new MenuPageModel(); // populate your model here return m; }
Layout
Seite können Sie diese Methode aufrufenGetTopMenu()
@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>
Angenommen, Ihr Modell ist eine Sammlung von Objekten (oder möglicherweise ein einzelnes Objekt). Führen Sie für jedes Objekt im Modell die folgenden Schritte aus.
1) Legen Sie das Objekt, das Sie anzeigen möchten, in den ViewBag. Beispielsweise:
ViewBag.YourObject = yourObject;
2) Fügen Sie oben in _Layout.cshtml eine using-Anweisung hinzu, die die Klassendefinition für Ihre Objekte enthält. Beispielsweise:
@ using YourApplication.YourClasses;
3) Wenn Sie in _Layout auf Ihr Objekt verweisen, besetzen Sie es. Sie können die Besetzung aufgrund dessen anwenden, was Sie in (2) getan haben.
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; }
}
Verwenden Sie IContainsMyModel in Ihrem Layout.
Gelöst. Schnittstellenregel.
Beispielsweise
@model IList<Model.User>
@{
Layout="~/Views/Shared/SiteLayout.cshtml";
}
Lesen Sie mehr über die neue @ model- Direktive