views:

3168

answers:

5

I'm working on a site which needs to be able to support two or more looks, changable at runtime. I'd hoped to be able to handle the change with a CSS switch, but it looks like I'll need to use a different masterpage for each design.

So, what's the best way to set the masterpage at runtime? Page.MasterPageFile can only be set in the Page.OnPreInit event. It looks like the solutions are to make all my pages inherit from a common base which handles the PreInit event, or to use an HttpModule which does that.

Any advice?

+1  A: 

Rather than two different master pages how about having one master that dynamically loads different user controls and content HTML literals?

Keith
+3  A: 

I've done this once before, I did exactly what you described (Made all pages inherit from a custom page with an OnPreInit event). Also I had a custom Application_PreRequestHandlerExecute in my Global.asax.cs for setting Page.StyleSheetTheme for doing image/css changes that didn't require a different Master Page.

thelsdj
A: 

It's easy enough to handle PreInit and insert the one line of code it takes to load the proper Master Page.

this.Page.MasterPageFile = "~/default.master";

In the absence of some compelling reason not to go this route, that's what I'd do, regardless of where you handle the PreInit.

James D
A: 

I'm curious what decides how the page should look? Is it the user clicking a button to change the theme? Is it based on the URL that was used to get to the site?

Code behind is supported in Master Pages, so you could put some logic in your one Master Page to decide what should be displayed.

I've seen several sites set cookies based on user clicks (to change font size, or page width), and then have different CSS files applied based on the value of those cookies. If no cookie is present, display a default look and feel.

EDIT:

Another thought here, if you are simply trying to switch out CSS is to set your style tag to run at the server, and assign properties to it at run-time. Once again this would require the use of a single master page, and putting code the code-behind of the master page, probably in the PreInit event handler.

Since I've never implemented this solution I'm not sure if the whole <HEAD> tag has to run at the server or not.


<html>
<head id="Head" runat="server">
<style id="StylePlaceholder" runat="server" type="text/css"></style>
</head>
Purple Ant
+1  A: 

I feel your pain. I searched for about an hour (if not more) for an issue to this, without success. It isn't just a cut and dry answer to say "just call it from PreInit on each page" when you have hundreds of pages. But then I realized that I was spending more time looking for a solution than it would have taken to just do it on each page.

However, I wanted to set the MasterPageFile based on a Profile property, so that would have been about 5 lines of code each page, a maintainability nightmare. And anyways, "don't repeat yourself", right?

So I created an Extension method in a module in the App_Code folder to make this easier and more maintainable.

Public Module WebFunctions

    <System.Runtime.CompilerServices.Extension()> _
    Public Sub SetMaster(ByVal page As Page)

        Dim pb As ProfileCommon = DirectCast(HttpContext.Current.Profile, ProfileCommon)

        If pb IsNot Nothing Then
            page.MasterPageFile = pb.MasterPage
        End If

    End Sub

End Module

And then on each page's PreInit, I just call this:

Protected Sub Page_PreInit(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreInit
        Me.SetMaster()
    End Sub
Paul