Frage Razor Nested Layouts mit kaskadierten Abschnitten


Ich habe eine MVC3-Seite mit Razor als View-Engine. Ich möchte, dass meine Website skinbar ist. Die meisten möglichen Skins sind so ähnlich, dass sie von einem gemeinsamen Master-Layout abgeleitet werden können.

Daher denke ich über dieses Design nach:

Planned view diagram

Allerdings würde ich gerne anrufen können RenderSection in der untersten Schicht, _Common.cshtmlund es einen Abschnitt rendern lassen, der in der obersten Ebene definiert ist, Detail.cshtml. Dies funktioniert nicht: RenderSection zeigt anscheinend nur Abschnitte an, die die nächste Ebene definiert haben.

Natürlich kann ich jeden Abschnitt in jedem Skin definieren. Zum Beispiel, wenn _Common muss anrufen RenderSection("hd") für einen Abschnitt definiert in DetailIch lege das einfach in jeden _Skin und es funktioniert:

@section hd {
    @RenderSection("hd")
}

Dies führt zu einer gewissen Duplizierung von Code (da jeder Skin nun denselben Abschnitt haben muss) und fühlt sich generell unordentlich an. Ich bin immer noch neu in Razor und es scheint, als würde ich etwas Offensichtliches vermissen.

Beim Debuggen kann ich die vollständige Liste der definierten Abschnitte in WebViewPage.SectionWritersStack sehen. Wenn ich RenderSection nur sagen könnte, dass ich die gesamte Liste durchgehen soll, bevor ich aufgäbe, würde es den Abschnitt finden, den ich brauche. Leider ist SectionWritersStack nicht öffentlich.

Alternativ könnte ich, wenn ich auf die Hierarchie von Layout-Seiten zugreifen und versuchen könnte, RenderSection in jedem anderen Kontext auszuführen, den Abschnitt finden, den ich brauche. Ich vermisse wahrscheinlich etwas, aber ich sehe keinen Weg, dies zu tun.

Gibt es einen Weg, dieses Ziel zu erreichen, abgesehen von der Methode, die ich bereits skizziert habe?


76
2018-04-02 20:16


Ursprung


Antworten:


Dies ist heute tatsächlich nicht möglich, wenn die öffentliche API verwendet wird (abgesehen von der Verwendung des Abschnitts Neudefinitionsansatzes). Vielleicht haben Sie etwas Glück mit privaten Überlegungen, aber das ist natürlich ein fragiler Ansatz. Wir werden versuchen, dieses Szenario in der nächsten Version von Razor einfacher zu machen.

In der Zwischenzeit, hier sind ein paar Blog-Beiträge, die ich zu dem Thema geschrieben habe:


35
2018-04-03 04:48



@helper ForwardSection( string section )
{
   if (IsSectionDefined(section))
   {
       DefineSection(section, () => Write(RenderSection(section)));
   }
}

Würde das den Job machen?


16
2017-10-15 21:37



Ich bin mir nicht sicher, ob das in MVC 3 möglich ist, aber in MVC 5 kann ich das mit folgendem Trick erfolgreich machen:

Im ~/Views/Shared/_Common.cshtml schreibe deinen gemeinsamen HTML-Code wie folgt:

<!DOCTYPE html>
<html lang="fa">
<head>
    <title>Skinnable - @ViewBag.Title</title>
</head>
<body>
@RenderBody()
</body>
</html>

Im ~/Views/_ViewStart.cshtml:

@{
    Layout = "~/Views/Shared/_Common.cshtml";
}

Alles, was Sie tun müssen, ist die Verwendung der _Common.cshtml als die Layout für alle Häute. Zum Beispiel, in ~/Views/Shared/Skin1.cshtml:

@{
    Layout = "~/Views/Shared/_Common.cshtml";
}

<p>Something specific to Skin1</p>

@RenderBody()

Jetzt können Sie die Skin als Layout in Ihrem Controller oder in Ihrer Ansicht basierend auf Ihren Kriterien festlegen. Beispielsweise:

    public ActionResult Index()
    {
        //....
        if (user.SelectedSkin == Skins.Skin1)
            return View("ViewName", "Skin1", model);
    }

Wenn Sie den obigen Code ausführen, sollten Sie eine HTML-Seite mit dem Inhalt von erhalten Skin1.cshtml und _Common.cshtml

Kurz gesagt, Sie legen das Layout für die (Skin-) Layout-Seite fest.


4
2017-12-29 15:13



Ich bin mir nicht sicher, ob Ihnen das weiterhilft, aber ich habe einige Erweiterungsmethoden geschrieben, um Abschnitte aus Teilbereichen zu "sprudeln", was auch für verschachtelte Layouts funktionieren sollte.

Einfügen von Inhalt in bestimmte Abschnitte aus einer Teilansicht ASP.NET MVC 3 mit Razor View Engine

Deklariere in untergeordneten Layout / Ansicht / teilweise

@using (Html.Delayed()) {
    <b>show me multiple times, @Model.Whatever</b>
}

Render in jedem Elternteil

@Html.RenderDelayed();

Siehe den Antwortlink für mehr Anwendungsfälle, wie zum Beispiel das Rendern eines verzögerten Blocks, selbst wenn er in einer wiederholenden Ansicht deklariert ist, das Rendern bestimmter verzögerter Blöcke usw.


1
2017-12-09 20:46