Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET MVC 3 Programmatically set layout

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?

like image 850
jaap Avatar asked Oct 16 '11 22:10

jaap


2 Answers

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;
        }
    }
}
like image 127
amiry jd Avatar answered Sep 27 '22 19:09

amiry jd


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.

like image 31
niaher Avatar answered Sep 27 '22 17:09

niaher