Dynamically Applying Themes To Your ASP.Net Site With A Sitemap

By | November 19, 2007

Ever run across a web site that used multiple themes, either page by page, or by some sort of grouping, such as the old divx.com site (click on the “Home”, “Movies” and “Software” tabs), and wondered how to do it in your own ASP.Net site? If so, then what I’m about to show you might be of interest. If not, read on anyway’s.

Quick Lesson/Review:

What are the different ways that you can specify and change the themes in an ASP.Net web site?

1) Classic Approach: Specify each CSS file for the theme in the section of each page.

<head runat="server">
    <title>Page Title</title>
    <link type="text/css" href="Theme1/default.css" />
</head>

One problem with this approach is that you have to open up each page and change the CSS file(s) for each theme, which could become time consuming depending on the size of the site, and how frequent the themes are changed.

2) Page Declaration: Specify the name of the ASP.Net Theme in the “theme” attribute of the Page Declaration.

>%@ Page Language="C#" theme="Theme1" CodeFile="Default.aspx.cs" %>

Compared to the Classic Approach, this is a quicker way to specify and change the theme of a page because you are specifying the ASP.Net Theme, and not each individual CSS file of the theme.

Like the Classic Approach you must open up and modify each page, which would give us the flexibility to change the theme on a page per page basis, but is a bit time consuming to modify and upload each one.

3) Web Config: This approach allows us to change the theme of all pages, by modifying only one file, the web.config.

<pages theme="Default" />

Although this is probably the quickest way to apply a theme to your site, it lack flexibility because it applies the theme to the entire site, and not per page.

4) Code: In its basic form, specifying the theme through code doesn’t give you any advantages over the previous methods. In fact, manually changing the theme through code on a page per page basis can be more of a PITA than using the Classic Approach or the Page Declaration.

protected void Page_PreInit(object sender, EventArgs e)
{
     this.Theme = "Theme1";
}

However, as I will attempt to show you, with a few more lines of code, this approach can simplify how a theme is applied, and give us the most flexibility.

Before I begin, there’s a few things I’d like to mention:

  • This code is a “Proof of Concept”, and not finalized, so there will be bugs.
  • I am not responsible for any damages that it may cause.
  • You may use this code in any way that you feel fit, whether it be for personal or commercial use.
  • If you use the code in your site, modified or not, I’d like to hear about it.
  • If you modify and/or improve the code, I also would like to hear about it so that I can improve my own code.
  • Please give credit, where credit is due.

Let’s Begin:

1) First, open up Visual Studio and create a new Visual C# ASP.Net Web Site (I’ll try to add a VB version later on).

2) Now add an App_Themes folder, and create three Theme folders in it. As you can see, I was original and named mine Theme1, Theme2 and Theme3. Within each of the Theme folders, add a Style Sheet file (StyleSheet.css), and set the background-color for each body tag to a different colour. I set mine to red, gold and green. There are a few million different colours to choose from, so you don’t have to choose the same as me if you don’t want to.

body {background-color: red;}
body {background-color: gold;}
body {background-color: green;}

3) Add a BasePage class file and a few Web Forms (aspx) pages to your project.

4) In each of the Web Forms’ Code File/Code Behind/Code Beside files, change the inheritance from System.Web.UI.Page to BasePage. A easy way to do this is to do a Quick Replace.

public partial class _Default : BasePage

5) Since the BasePage class is the “Base Page” for our site, we will need to tell it that it inherits from System.Web.UI.Page.

public class BasePage : System.Web.UI.Page

In case you’re a bit confused, all I’ve done is create a Base Page class that sits between the System.Web.UI.Page and our Web Form pages. By doing this, we are now able to add new methods and properties that each page will inherit, as well as override existing methods that are found in System.Web.UI.Page.

6) Under the BasePage constructor, we are going to override OnPreInit(), and set the Theme property to one of our themes that we created above.

protected override void OnPreInit(EventArgs e)
{
     string _theme = "Theme1";
     this.Theme = _theme;

     base.OnPreInit(e);
}

7) Now press F5. Hopefully your default browser will open up and have the background color that you set in the theme. For me, my page was red.

8) Close the browser and go back to your project. Now add a “Site Map” to your site.

If you’ve never used an ASP.Net Site Map before, check out “ASP.NET Site Maps” on MSDN.

For those of you who have used the Site Map before, did you know that you can add your own custom attributes to each node? I discovered this a few years ago, and first used it to add onmouseover images for a toolbar.

9) With your Site Map opened, add a siteMapNode for each of the pages that you created earlier, and fill in the url attribute with the name of the page (“Default.aspx”, “Default2.aspx”, …), and give the title attribute a value (“Page 1″, “Page 2″, …). Now add a add a theme attribute to each siteMapNode, and set its value to a name of one of the Theme folders (“Theme1″, “Theme2″, ….). Just ignore the description attribute, we won’t be needing it.

<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
 <siteMapNode url="Default.aspx" title="Page 1" theme="Theme1">
  <siteMapNode url="Default2.aspx" title="Page 2" theme="Theme2"/>
  <siteMapNode url="Default3.aspx" title="Page 3" theme="Theme3">
   <siteMapNode url="Default4.aspx" title="Page 4" theme="Theme1"/>
  </siteMapNode>
  <siteMapNode url="Default5.aspx" title="Page 5" theme="Theme3">
   <siteMapNode url="Default6.aspx" title="Page 6" theme="Theme3">
    <siteMapNode url="Default7.aspx" title="Page 7" theme="Theme1"/>
    <siteMapNode url="Default8.aspx" title="Page 8" theme="Theme2"/>
   </siteMapNode>    
  </siteMapNode>
 </siteMapNode>
</siteMap>

So far so good?

10) Go back to your BasePage class, and into its OnPreInit() that we added above. In here, we are going to add a few lines of code that will read from the Site Map.

11) For this to work, we will need to find the CurrentNode from the Site Map for the page that the user is on, and then read the theme attribute that we added to its siteMapNode. Remove the previous code from the OnPreInit(), and replace it with what’s below.

//Retrieve the node from the sitemap for the current page.
SiteMapNode currentNode = SiteMap.CurrentNode;

12) Once we have have the currentNode, we need the value of its theme attribute.

// If the node for this page is found in the sitemap, 
// then try to retrieve a theme
if (currentNode != null)
{
    // If the node's key 'theme' for this page exists, 
    // then set the theme variable to the value.
    if (!String.IsNullOrEmpty(currentNode["theme"]))
    {
        theme = currentNode["theme"];
    }   
    this.Theme = theme;
}
base.OnPreInit(e);

Now press F5 and go to each of the pages that you created. If you specified a different value for each of the theme attributes, each page should be a different colour.

Neat eh?

But wait, there’s more.

What we have done, is allow for each page to have its own theme. But what if we wanted a group of pages to all have the same theme, like the Movies and Software section in the old divx.com site that I mentioned earlier?

13) From the code above, replace the “this.Theme = theme;” line with the following:

else
{
    currentNode = currentNode.ParentNode;

    // If the node's key 'theme' doesn't exist, 
    // then loop through each of the parent nodes until a 'theme' is found.
    while (currentNode != null && String.IsNullOrEmpty(currentNode["theme"]))
    {
        currentNode = currentNode.ParentNode;
    }

    
// Double check that the node that was found isn't null or empty
    // (it shouldn't be, because we checked above), and set the theme
    // variable to the value found.
    if (currentNode != null && !String.IsNullOrEmpty(currentNode["theme"]))
    {
        theme = currentNode["theme"];
    }
}
// You can never be too careful. Make sure that the theme variable isn't null,
// and contains a value. If so, then set the page's Theme property to it.
if (!String.IsNullOrEmpty(theme))
{
    this.Theme = theme;
}

and remove the space that might be above the “else“.

14) Last step, I promise. Go back to the Site Map, and remove a few of the theme attributes.

<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
 <siteMapNode url="Default.aspx" title="Page 1" theme="Theme1">
  <siteMapNode url="Default2.aspx" title="Page 2"/>
   <siteMapNode url="Default3.aspx" title="Page 3" theme="Theme3">
    <siteMapNode url="Default4.aspx" title="Page 4"/>
   </siteMapNode>
   <siteMapNode url="Default5.aspx" title="Page 5" theme="Theme3">
   <siteMapNode url="Default6.aspx" title="Page 6" theme="Theme3">
    <siteMapNode url="Default7.aspx" title="Page 7"/>
     <siteMapNode url="Default8.aspx" title="Page 8" theme="Theme2"/>
    </siteMapNode>    
   </siteMapNode>
</siteMapNode>
</siteMap>

I’ve removed the theme attribute from “Page 2“, “Page 4” and “Page 7“.

15) Okay, I lied. Press F5 once more, and go to each page. If you structured your site like I did, “Page 2” should be using “Theme1“, instead of the previous “Theme2“. “Page 4″ should be using “Theme3” instead of “Theme1″, and “Page 7” should be using “Theme3” instead of “Theme1“.

In case you missed it in step 13, what we have done is check to see if the currentNode had a theme, and if not, we looped through each ParentNode until it found a theme with a value. This loop will continue all of the way up until it hits the Default.aspx siteMapNode.

One thing you might want to do though, is go into your web.config file, and set a default theme, so that no matter what, every page will have a theme.

<pages theme="Theme1" />

 

Download:

Here’s the project as a zip. It includes a few more pages, and the following themes.

4 thoughts on “Dynamically Applying Themes To Your ASP.Net Site With A Sitemap

  1. Pingback: DotNetKicks.com

  2. Pingback: roScripts - Webmaster resources and websites

  3. Pingback: Tom's Blog

Leave a Reply

Your email address will not be published. Required fields are marked *