In a .NET Razor Web Application i'm trying to programmatically set the Layout
. I can not use _ViewStart.cshtml
and don't wont to set the @{ Layout = "..." }
on every page. This is what I have come up with:
A base WebViewPage
class:
public abstract class SitePage<T> : System.Web.Mvc.WebViewPage<T>
{
private object _layout;
public new dynamic Layout { get { return _layout; } }
public override void InitHelpers()
{
base.InitHelpers();
_layout = "~/Themes/" + Settings.Theme + "/Views/_Layout.cshtml";
}
}
And in the application web.config
I specify all view to use this base page. But the Layout
is never used it seems. What could be wrong here?
The WebViewPage
class inherits from WebPageBase
that has a property named Layout
like:
public override string Layout { get; set; }
You can override the Layout
property, or change your _layout logic to achieve your purpose. For example:
public abstract class SitePage<T> : System.Web.Mvc.WebViewPage<T> {
// set this modifier as protected, to make it accessible from view-pages
protected string _layout{
get {
return base.Layout;
}
set {
base.Layout = value;
}
}
public override void InitHelpers() {
base.InitHelpers();
_layout = "~/Themes/" + Settings.Theme + "/Views/_Layout.cshtml";
}
}
and/or in a view-page, you can set it too:
@{
_layout = "_Your_Special_Layout.cshtml";
}
UPDATE: using a flag to avoid stack-over-flow in assigning _layout more that once:
public abstract class SitePage<T> : System.Web.Mvc.WebViewPage<T> {
public bool LayoutAssigned {
get {
return (ViewBag.LayoutAssigned == true);
}
set {
ViewBag.LayoutAssigned = value;
}
}
// set this modifier as protected, to make it accessible from view-pages
protected string _layout{
get {
return base.Layout;
}
set {
base.Layout = value;
}
}
public override void InitHelpers() {
base.InitHelpers();
if(!LayoutAssigned) {
_layout = "~/Themes/" + Settings.Theme + "/Views/_Layout.cshtml";
LayoutAssigned = true;
}
}
}
I tried to achieve the same just now by implementing a custom WebViewPage, however changing WebViewPage.Layout within my custom class didn't have any effect (as you have also discovered).
Eventually I ended up changing my _ViewStart.cshtml to have this code:
@{
this.Layout = this.Request.QueryString["print"] == "1"
? "~/Views/Layout/_Print.cshtml"
: "~/Views/Layout/_Layout.cshtml";
}
It might not be implemented how you wanted it, but it certainly does keep things dry and that is the main point.