我有一个使用Razor作为其视图引擎的MVC3站点。我希望我的网站可以换肤。大多数可能的皮肤都足够相似,可以从共享的主布局中获得。
因此,我正在考虑这个设计:
但是,我希望能够在底层RenderSection
中调用_Common.cshtml
,并让它呈现在顶层Detail.cshtml
中定义的部分。这不起作用:RenderSection
显然只渲染下一层定义的部分。
当然,我可以定义每个皮肤中的每个部分。例如,如果_Common
需要为RenderSection("hd")
中定义的部分调用Detail
,我只需将其放在每个_Skin
中,然后就可以了:
@section hd {
@RenderSection("hd")
}
这导致一些代码重复(因为每个皮肤现在必须具有相同的部分)并且通常感觉很乱。我还是Razor的新手,似乎我可能会遗漏一些明显的东西。
调试时,我可以在WebViewPage.SectionWritersStack中看到已定义部分的完整列表。如果我可以告诉RenderSection在放弃之前查看整个列表,它会找到我需要的部分。唉,SectionWritersStack是非公开的。
或者,如果我可以访问布局页面的层次结构并尝试在每个不同的上下文中执行RenderSection,我可以找到我需要的部分。我可能遗漏了一些东西,但我认为没有办法做到这一点。
除了我已经概述的方法之外,有没有办法实现这个目标?
答案 0 :(得分:35)
这实际上今天不可能使用公共API(除了使用部分重定义方法)。使用私人反思可能会有一些运气,但这当然是一种脆弱的方法。我们将研究在下一版Razor中使这种情况更容易。
与此同时,这里有几篇关于这个主题的博客文章:
答案 1 :(得分:17)
@helper ForwardSection( string section )
{
if (IsSectionDefined(section))
{
DefineSection(section, () => Write(RenderSection(section)));
}
}
这会完成这项工作吗?
答案 2 :(得分: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.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
简而言之,您将为(皮肤)布局页面设置布局。
答案 3 :(得分:1)
不确定这是否对您有帮助,但我写了一些扩展方法来帮助&#34;冒泡&#34;部分内部的部分,也适用于嵌套布局。
Injecting content into specific sections from a partial view ASP.NET MVC 3 with Razor View Engine
在子布局/视图/部分
中声明@using (Html.Delayed()) {
<b>show me multiple times, @Model.Whatever</b>
}
以任何父级渲染
@Html.RenderDelayed();
有关更多用例,请参阅答案链接,例如,即使在重复视图中声明,也只渲染一个延迟块,渲染特定延迟块等等。