webentwicklung-frage-antwort-db.com.de

ASP.NET MVC Razor Modell an Layout übergeben

Was ich sehe, ist eine Zeichenfolge-Layout-Eigenschaft. Aber wie kann ich ein Modell explizit an das Layout übergeben?

84
SiberianGuy

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.

65
  1. Fügen Sie Ihrem Controller (oder Basis-Controller) eine Eigenschaft mit dem Namen MainLayoutViewModel (oder was auch immer) mit dem beliebigen Typ hinzu, den Sie verwenden möchten.
  2. Instanzieren Sie im Konstruktor Ihres Controllers (oder Basiscontrollers) den Typ und setzen Sie ihn auf die Eigenschaft.
  3. Setzen Sie es auf das Feld ViewData (oder ViewBag)
  4. Wandeln Sie auf der Layout-Seite diese Eigenschaft in Ihren Typ um.

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


Mvc Core scheint den Inhalt von ViewData/ViewBag beim ersten Aufruf jeder Aktion zu sprengen. Dies bedeutet, dass das Zuweisen von ViewData im Konstruktor nicht funktioniert. Was funktioniert, ist jedoch die Verwendung einer 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;
            }
        }
    }
70
BlackjacketMack

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

23
Yakir Manor

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. 

11
Arya Sh

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");
}
8
Oskar Sjöberg

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.

1
computrius

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.

1
Laz Ziya

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.

0
HappyPawn8