剃刀嵌套布局与级联部分

我有一个使用Razor作为视图引擎的MVC3网站。 我希望我的网站可以换肤。 大多数可能的皮肤足够相似,可以从共享的主布局派生。

所以我正在考虑这个devise:

计划的视图图

但是,我希望能够调用底层的RenderSection中的_Common.cshtml ,并使其在最上层的Detail.cshtml定义一个部分。 这不起作用: RenderSection显然只渲染定义下一层的部分。

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

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

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

debugging时,我可以在WebViewPage.SectionWritersStack中看到完整的定义部分列表。 如果我能告诉RenderSection在放弃之前查看整个列表,它会find我需要的部分。 唉,SectionWritersStack是非公开的。

或者,如果我可以访问布局页面的层次结构,并尝试在每个不同的上下文中执行RenderSection,我可以find我需要的部分。 我可能错过了一些东西,但我没有看到任何方式来做到这一点。

除了我已经提到的方法之外,有什么方法可以实现这个目标吗?

这实际上是不可能的今天使用公共API(除了使用部分重新定义方法)。 使用私人reflection可能会有一些运气,但这当然是一个脆弱的方法。 我们将考虑在下一个Razor版本中使这个场景更容易。

与此同时,这里有几篇关于这个主题的博文:

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

这会做这个工作吗?

我不知道如果这是可能的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.cshtml作为所有皮肤的Layout 。 例如,在~/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); } 

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

总之,您将设置(皮肤)布局页面的布局。

不知道这是否会对你有所帮助,但是我写了一些扩展方法来帮助从部分内部“冒泡”部分,这也适用于嵌套布局。

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

在子布局/视图/部分声明

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

在任何父母中呈现

 @Html.RenderDelayed(); 

查看更多用例的答案链接,例如即使在重复视图中声明,渲染一个延迟块,渲染特定的延迟块等,也是如此。