01 August, 2007

Loading themes programmatically

I've made a little progress on the database diagram, but admittedly, that is not the most fun aspect of life. So I have been concentrating a little more the past couple of days on the front-end. I have been playing with themes, skins and styles.

One thing I wanted to be able to do was change the theme programmatically. I know this should be possible, but dog-gone if it wasn't a pain in the arse to figure out! After oodles of Google searches, I finally found this article at ASP Alliance. Good detail and explains a lot.

In a nutshell, the best way to programmatically change themes is to create a base class. I named mine BasePage.cs. This class inherits System.Web.UI.Page. Other pages (not the .master pages though) inherit this BasePage instead of System.Web.UI.Page. Wait, I think I'm getting a little ahead of myself. Let me back up a little.

One can programmatically set the page theme (this.Page.Theme), but only in the Page_PreInit(object sender,System.EventArgs e) method. However, this method is not valid in any .master file. Therefore, this method must be set in the actual .aspx files. There are two ways to do this, put the Page_PreInit method in each and every page file. This can cause issues if one wants to change the way they programmatically load themes (i.e., via cookies, session, use-select etc). The better way is to create a separate class which inherits from System.Web.UI.Page, and which all other .aspx classes inherit (instead of the System.Web.UI.Page class).

Okay, now that I have that out of the way, back to the meat. In the BasePage class I added a Page_PreInit method. In this method is where I set the theme.

void Page_PreInit(object sender, System.EventArgs e)
{
if (Session["Theme"] != null && Session["Theme"].ToString().Length > 0)
this.Page.Theme = Session["Theme"].ToString();
else
this.Page.Theme = "Default";
}

For testing, I created three themes, Default, LeftSidebar and RightSidebar. In the .master file I created a table with a 'header' row which contains only 1 column, a 'body' row which contains three columns and a 'footer' row which contains only 1 column. I assigned classes to each of the columns. In the stylesheet in the theme folders I defined how the table should appear. For instance, for easy identification in the Default theme's stylesheet, I put the header column background to aqua, the footer to lime the left side bar to read the main body to white and the right side bar to blue. This way, it is very easy to see what is displaying proper and what isn't.

For the LeftSidebar and RightSidebar themes' stylesheet, I simply made the column width 0px and the background color transparent (for which ever column was going to not be seen).

.leftSideBar
{
width:15%;
background-color:Red;
vertical-align:top;

}
.rightSideBar
{
width:0px;
background-color:Transparent;
vertical-align:top;
}

Am I making any sense here? Sometimes I think I start rambling, and then I don't very well explain myself. Anyway...

To select which theme to load, I placed a DropDownList in the header section of the table. The list contains four items "Select Theme","Default","Left Side Bar Theme" and "Right Side Bar Theme". Then I added an SelectedIndexChanged event handler and set a Session variable to the selected value of the DropDownList control.

protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
if (this.DropDownList1.SelectedIndex > 0)
{
Session["Theme"] = this.DropDownList1.SelectedItem.Value;
Response.Redirect(Request.Url.AbsoluteUri);
}
}

Basically, this will cause two postbacks. The first when the DropDownList control selection is changed, and the second after the Session["Theme"] value is set. It is neccessary to do another post back at this time because, in the hierarchy of how things happen in ASP.NET, the Page_PreInit method happens before the Page_PostBack and anything that follows that. Since the Session variable is not set until after the Page_PreInit is executed, it is necessary to post back again after setting the Session["Theme"] variable.

This will programmatically change the themes based on what the user selects. Other ways of loading themes I will be investigating are via cookies, and database entries.

Thanks for stopping by, you can wake up now!

2 comments:

Anonymous said...

A very good post. Accurate and concise.

Anonymous said...

The Windows Forms Theme control loads a theme package to .NET project via the ThemeResolutionService