tags:

views:

47

answers:

1

I have the requirement to support themeing of my site's pages. The way I am doing this is by dynamically choosing a master page based on the current theme.

I have setup a directory structure like so

/shared/masterpages/theme1/Master1.master /shared/masterpages/theme1/Master2.master /shared/masterpages/theme1/Master3.master

/shared/masterpages/theme2/Master1.master /shared/masterpages/theme2/Master2.master /shared/masterpages/theme2/Master3.master

And I am still using the page directive in the view

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/shared/masterpages/theme1/Master1.Master"%>

I would still like to leverage the view's MasterPageFile property and just change the theme directory.

I can only think of three ways to do this none of them which sound great.

  1. Create a custom BaseView class that uses OnPreInit to change the theme like this
  2. Create some xml file or database table that links each view to a master page file and then set this in the controller.
  3. Build some tool that reads all the views and parses them for their masterpagefile, (similar to 2 but could be done at run time potentially.)

Option 1 seems the best option to me so far. Does anyone else have any thoughts on how to do this?

+2  A: 

Updated suggestion:

Since my original suggestion didn't work out as I had expected, here's a possible way to work around it, while still keeping your action methods clean, and minimizing repetition of code:

  1. Create an ActionResult that adds the master name/theme name/whatever info you need to pick the correct master page into ViewData["masterInfo"] (or something similar).
  2. Create a base class which themeable views inherit. Your base class should, of course, inherit from System.Web.Mvc.ViewPage. If you need, also create a generic version that inherits from .ViewPage<T>.
  3. In your base class, create a construction method that selects the correct master page based on ViewData["masterInfo"]. I'm not sure if there's a need or not, but don't forget to run the base constructor, either before or after your code, if there is one that needs to run.
  4. Decorate all relevant actions with the attribute, and set their views to inherit your base class instead of System.Web.Mvc.ViewPage.

Original post:
Why not have an ActionFilter, that can be applied on controller level, that sets the MasterPageFile property of the view? If you override OnActionExecuted, it shouldn't be too tricky to test if the result was a ViewResult and in that case change the property to the correct value.

Tomas Lycken
My understanding is that in OnActionExecuted you can't see the MasterPageFile property set in the view itself. You can only change master page files that are set by the controller. Is this incorrect?
Jeff
I haven't actually tried this out - I just figured the best way to do it would be via an ActionFilter, and since you need the result to be instantiated, it would have to be executed after the controller action. Have you tried working with this, and found problems? If yes, what problems?
Tomas Lycken
I just tested and in OnActionExecuted you just have the ViewResult but the view itself has not been loaded yet so you don't see the masterpage that is defined in the page directive of the view only master pages set by the controller.
Jeff
@Jeff, please see my updated suggestion.
Tomas Lycken
Thanks for the suggestion Tomas. I still think approach 1 that I linked to in my original post is the best option I have seen yet.
Jeff