带级联截面的Razor嵌套布局


79

我有一个使用Razor作为其视图引擎的MVC3网站。我希望我的网站可以换肤。大多数可能的外观非常相似,以至于它们可以从共享的主版面派生。

因此,我正在考虑以下设计:

平面图

但是,我希望能够RenderSection在最底层调用_Common.cshtml,并使其呈现在最顶层定义的部分Detail.cshtml。这是行不通的:RenderSection显然只渲染下一层定义的部分。

当然,我可以定义每个皮肤中的每个部分。例如,如果_Common需要调用RenderSection("hd")中定义的部分Detail,我只需将其放在每个部分中即可使用_Skin

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

这会导致代码重复(因为每个皮肤现在必须具有相同的部分),并且通常感到混乱。我还是Razor的新手,似乎我可能缺少明显的东西。

调试时,我可以在WebViewPage.SectionWritersStack中看到已定义部分的完整列表。如果我可以告诉RenderSection在放弃之前浏览整个列表,它将找到我需要的部分。Section,SectionWritersStack是非公开的。

另外,如果我可以访问布局页面的层次结构并尝试在每个不同的上下文中执行RenderSection,则可以找到所需的部分。我可能缺少了一些东西,但是我看不到任何办法。

除了我已经概述的方法之外,还有其他方法可以实现此目标吗?

Answers:


35

实际上,今天使用公共API是不可能的(除了使用部分重定义方法之外)。使用私有反射可能会有些运气,但这当然是一种脆弱的方法。我们将在下一个版本的Razor中尝试简化此方案。

同时,这里有一些我写过的关于这个主题的博客文章:


3
感谢您的回应,我一直在使用这种语法(如上)来处理嵌套部分:@section hd {@RenderSection(“ hd”)} ...实际上对我有用,看起来我可以复制现有的嵌套母版页。我想我对这个问题有误解,并认为这行不通。
Mark Redman

2
问题和答案都大有帮助,我也同意在下一个版本的Razor中应该使此操作更容易。而且,您还应该使部分视图也能够实现部分的可能性,目前尚不支持。
母马

1
@Shrike我认为在这方面没有任何改变。您可以在uservoice网站上输入功能请求,也可以在codeplex
2012年

1
@marcind看看我的答案。我认为这是OP要求的。对?
Alireza Noori 2013年

1
MVC 5退出。任何更新?Alirzea说他找到了一个解决方案,但是它似乎与OP的问题不匹配,因为它根本没有引用任何章节。
Snekse

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

这样行吗?


您在中间层中使用它吗?与这个扩展类差不多吗?如果是这样,那么在重新声明节而不是解决问题时更方便。请确保我理解,因为我来不及讨论。
drzaus 2012年

对我来说,这是唯一有效的解决方案。如果有节在基础布局中有条件地呈现,则MVC会抛出运行时错误,除非在中间层中有条件地定义了该节(像这样)。谢谢@兰迪!
迈克尔

是否可以转发当前定义的所有节?
nvirth

4

我不确定在MVC 3中是否可行,但是在MVC 5中我可以使用以下技巧成功做到这一点:

~/Views/Shared/_Common.cshtml编写常见的HTML代码时,例如:

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

~/Views/_ViewStart.cshtml

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

现在您所要做的就是_Common.cshtmlLayout用作所有皮肤。例如,在~/Views/Shared/Skin1.cshtml

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

<p>Something specific to Skin1</p>

@RenderBody()

现在,您可以根据条件将外观设置为控制器或视图中的布局。例如:

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

如果你运行上面的代码,你应该得到一个HTML页面的两个内容Skin1.cshtml_Common.cshtml

简而言之,您将为(皮肤)布局页面设置布局。


我在使用这种方法时遇到了问题,因为部分不可见。我在blogs.msdn.microsoft.com/marcinon/2010/12/15/…
Spikolynn '16

1

不知道这是否对您有帮助,但是我写了一些扩展方法来帮助从局部中“鼓起”部分,这也适用于嵌套布局。

使用Razor View Engine从局部视图ASP.NET MVC 3将内容注入特定部分

声明子布局/视图/部分

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

在任何父母中渲染

@Html.RenderDelayed();

有关更多用例,请参见答案链接,例如即使在重复视图中声明也仅渲染一个延迟的块,渲染特定的延迟的块等。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.