Skin Treatment

Exploiting ASP.NET 2.0 Themes

VBUG Spotlight

LANGUAGES: C#

ASP.NET VERSIONS: 2.0

 

Skin Treatment

Exploiting ASP.NET 2.0 Themes

 

By Phil Winstanley

 

You ve probably read some about ASP.NET 2.0 themes but just in case you ve had your head in a bucket for the past few months, here s a quick overview.

 

Themes in ASP.NET 2.0 allow developers and designers to work together to offer different looks and feels for a Web site, using nothing more than the Theme property of a page, a CSS file, some images, and what is lovingly called a skin file. ASP.NET 2.0 is designed so that your Web sites can be extensively themed.

 

In this article we ll go through a step by step approach to themes in ASP.NET 2.0 and how to get the most out of themes as they are intended to be used. We ll also run through some other great uses for themes when it comes to localization of your applications.

 

Why Should I Care about Themes?

It might well be that you develop an application once, with no intention of there being multiple visual designs for the same site. But I d still argue it s a good idea to use themes so before you flick to the next article, make sure you read the next couple of paragraphs while I try to persuade you.

 

You may only have one application to support, but what happens when someone decides they want to change the look of that application? For example, what if the company s corporate font changes from Ariel to Tahoma? Unless you re running with well structured Cascading Style Sheets and themes, you might be in for a big chunk of work, depending on the size of a site.

 

Another good reason to use themes as opposed to embedding the style information directly within your pages and controls is that one day, you may be asked to create another site that looks exactly like an existing site you have except for a few small changes. When you create a site with themes it s really easy to transfer a theme from one site to another by simply copying the themes folder across.

 

What Constitutes a Theme?

Themes are really simple when you get right down to it, but they are separated into several portions. There s a folder for each theme you want your site to have. The name of the folder becomes the name of the theme; if you add a folder to the App_Themes folder named Blue , then the theme is named Blue .

 

Each theme folder can have sub folders, which you can use to store images, style sheets, and skin files. Any type of image can be stored anywhere within the theme folder, including .jpg, .gif, .png, .bmp, and others. Cascading Style Sheets (.css) files should also be added to the theme folder where you can set styles as you would normally:

 

body

{

 font-family:Verdana;

 font-size:10pt;

 font-weight:bold;

 color:Black;

 background-color:White;

}

 

In addition to the images and CSS files, there is a new type of file named skin files, which are specifically designed for themes. Skin files define the properties of individual controls or groups of controls on a per theme basis. Skin files consist of entries that pertain to other server controls, and come in two flavors those that are given an ID:

 

 ImageUrl="Logo.gif" />

 

and those that apply to all controls of a particular type:

 

 

There can be only one instance of controls without a SkinId per skin file, as those controls without a SkinId apply to all instances of a particular control.

 

It s worth noting that you can also store any other files you wish inside a theme s folder, such as a .exe or .zip. This enables you to have themed downloads, as well as a themed visual design, which is very useful if you have one site that you want to re-skin for different companies or purposes.

 

Multiple Themes

If having one theme is useful, then having many themes is great! Setting up multiple themes on the same site is as easy as creating new folders; in fact, that s exactly how to do it.

 

Each theme you require your site to have gets its own folder, in which you can place the skin file, css files, and any images. Figure 1 shows the App_Themes folder, which shows several different themes such, as Audi and Volkswagen.

 


Figure 1: The App_Themes folder has multiple themes.

 

You Want to Redecorate? Again?

Sometimes working in Web development we feel like we should be on one of those television lifestyle programs where some interior designer or landscape gardener is constantly nagging us to change the way things look and create Zen on our sites. More often than not it is the job of the developer to tweak the look and feel of a site, but not any more!

 

Fortunately we can change a theme at run time, which means no recompiles for the sake of a different font or a new image! Here is a user control that will inspect the App_Themes folder, list all the themes it finds, and add them to a DropDownList as items:

 

<%@ Control Language="C#" AutoEventWireup="true" CodeFile=

 "ChangeTheme.ascx.cs" Inherits="ChangeTheme" %>

 

 "server" Text="Set" />

 

It also makes sure the current theme is selected in the dropdown list (the server-side code is shown in Figure 2).

 

protected void Page_Load(object sender, EventArgs e)

{

 if (!Page.IsPostBack)

 {

   if (Directory.Exists(Server.MapPath("~/App_Themes")))

   {

     string[] subdirs = Directory.GetDirectories(

      Server.MapPath("~/App_Themes"));

     foreach (string dir in subdirs)

     {

       DirectoryInfo dirInfo = new DirectoryInfo(dir);

       Themes.Items.Add(dirInfo.Name);

       if (Themes.Items.FindByText(Page.Theme) != null)

       {

           Themes.SelectedIndex = Themes.Items.IndexOf(

            Themes.Items.FindByText(Page.Theme));

       }

     }

   }

 }

}

Figure 2: A user control to inspect the App_Themes folder.

 

On the page itself, we add a small snippet of code to the Page_PreInit event, which will check to see if someone has applied a new theme to ensure it s selected, remembered in the session, and displayed:

 

protected void Page_PreInit(object sender, EventArgs e)

{

 if ((Request.Form["ChangeTheme1$Themes"] != null) || (

  Session["Theme"] != null))

 {

  this.Page.Theme = (Request.Form["ChangeTheme1$Themes"]

   != null) ? Request.Form["ChangeTheme1$Themes"] :

   Session["Theme"].ToString();

  Session["Theme"] = (Request.Form["ChangeTheme1$Themes"]

   != null) ? Request.Form["ChangeTheme1$Themes"] :

   Session["Theme"].ToString();

 }

}

 

Figure 3 shows a sample page that is loading with the default theme; this is the first load of the page.

 


Figure 3: Loading the default theme.

 

When a new theme is selected from the dropdown box on the right and you click the Set button, you ll instantly see the new skin, which has been picked up to show new images using a different style sheet, showing different images and even displaying different text (see Figure 4).

 


Figure 4: Select a new theme to display a new skin.

 

As you can see, themes are very powerful and can be used at design and run time to dramatically change the way your sites are rendered.

 

One way you can extend this functionality is by checking the URL that someone is viewing the site with, allowing you to have different themes that change based on URL. This is as simple as calling your themes www.mysite.com and www.myothersite.com and having this line in the Page_PreInit event of each page:

 

this.Theme = Request.ServerVariables["SERVER_NAME"];

 

While changing by domain name is useful in a multi-company/portal-style site, what s more useful is the ability to support different browsers:

 

this.Theme = Request.Browser.Browser;

 

Another way is to detect the preferred language of the user visiting your site and switch the theme based on that:

 

if (Request.UserLanguages != null)

{

 this.Theme = Request.UserLanguages[0];

}

 

Speaking of languages leads us into our next section: abusing the theme system to make multilingual sites.

 

Where s My Babelfish?

ASP.NET 2.0 has some fantastic new features for making your site work in a multilingual manner using resource files and automatic detection of a user s preferred language. However, something that is not quite so easy is dealing with various visual designs using only the Internationalization features in ASP.NET 2.0; this is where themes can pick up the slack.

 

It s possible to make a site multilingual without having to go near the Globalization features built into ASP.NET, without having to write more than a few lines of code, and without having to tear your hair out.

 

By creating a theme for each culture you want to support, such as American English (en-US), Belgian Flemish (nl-BE), or Belgian French (fr-BE), you can instantly make your Web site multilingual.

 

This is done by assigning the textual copy for the site to Label controls using the Text property. After this has been done, it s a trivial thing to have the text placed into different skin files for each different culture, then have that text translated to the appropriate language.

 

Here s the entry for WelcomeText in the skin file for the French theme (see Figure 5):

 

 "Voitures d'occasions avec garantie des professionnels" />

 


Figure 5: The French version.

 

The Flemish version looks similar to the French, but is in a different language because it loads the skin file from the /App_Themes/Renault (Flemish)/ folder and picks up the different text (see Figure 6). In the skin file for the Flemish theme there is a completely different value for the Text property of the WelcomeText label:

 

 "Gebruikte wagens van de professionele bron" />

 


Figure 6: The Flemish version.

 

Extend the above approach to the entire site and not only have you got a file you can give to the marketing people at your company so they can change the copy without them ever having to go near a resource file, but you ll also make it incredibly simple to make the site multilingual at a later date.

 

Now that we can deal with all the text on our site, what about the images? Every site has images; a usual place you ll find images is in the main navigation of a site, which keeps designers happy and really makes a good impact on the overall site design.

 

Images are notorious when it comes to multilingual sites. As a binary file, they re much more difficult to deal with; normally, you ll have to compile images into resource files and use the System.Resources namespace to stream them out to the client. Luckily for us, we can bypass all of this by using themes.

 

In the skin file you can specify the ImageUrl property of the System.Web.UI.WebControls.Image control, combine this with a theme by placing localized images into the correct theme s folder, and instantly have multilingual image controls:

 

 "PrinterFriendlyFormat.gif" />

 

It s also possible to choose what to display for different themes by using the Visible property of controls. For example, you might not want to show the British Car Magazine label to anyone except the British, so set it to Visible= False on the page, and then in the skin file have an entry for the label that makes the control visible:

 

 Visible="True" />

 

Great, I Can Theme Everything! ... Ahem, Not Exactly

Out of the hundred or so controls that ship with ASP.NET, only some actually support being themed everything else is not available to you for skinning. You ll get a lovely red error message if you try to apply a theme to a control in your skin file that doesn t support skinning:

 

The control type System.Web.UI.HtmlControls.HtmlTableCell cannot be themed.

 

Until now, it s been a process of trial and error determining which controls can and cannot be skinned. Wouldn t it be nice to have a reference table? Your wish is my command! Figure 7 shows a self-contained method that you can simply drop onto a page and execute (although you won t have to change anything to run it, note that if you re running a different version of the .NET Framework, or are running on Windows NT, you might need to change the location to which I ve set SystemWebDll).

 

public void WhatCanBeThemed()

{

 string SystemWebDll = (@"c:\Windows\microsoft.net\

  Framework\v2.0.50215\System.Web.dll");

 if (System.IO.File.Exists(SystemWebDll))

 {

   System.Reflection.Assembly assemblyInformation =

     System.Reflection.Assembly.LoadFrom(SystemWebDll);

   System.Type[] assemblyTypeInformation =

    assemblyInformation.GetTypes();

   foreach (Type TypeInformation in assemblyTypeInformation)

   {

     if ((TypeInformation.IsVisible))

     {

       System.Reflection.MemberInfo info =

        TypeInformation;

       object[] attributes =

        info.GetCustomAttributes(true);

       for (int i = 0; i < attributes.Length; i++)

       {

         bool HasAttribute = (

          "System.Web.UI.ThemeableAttribute" ==

          attributes[i].ToString());

         if (HasAttribute)

         {

             bool IsThemable = ((

              System.Web.UI.ThemeableAttribute)

              attributes[i]).Themeable;

             if (IsThemable)

             {

               Response.Write(TypeInformation.FullName +

                 "
");

             }

         }

       }

     }

   }

 }

 else

 {

   throw new System.Exception(SystemWebDll +

    " was not found, point SystemWebDll at the

    System.Web.dll.");

 }

}

Figure 7: This method will list all the controls in System.Web.dll that support themes and have themes enabled.

 

When the code in Figure 7 is run, you ll see a list of types that are valid for skinning, like this:

 

System.Web.UI.WebControls.DataBoundControl

System.Web.UI.WebControls.AdRotator

System.Web.UI.WebControls.Label

System.Web.UI.WebControls.BaseValidator

...

 

Now that you have the full list, you can use it as a reference for the controls you re allowed to add into your skin files. Better still, by modifying one line in Figure 7 you can generate a skin file template; simply swap out:

 

Response.Write(TypeInformation.FullName + "
");

 

with this:

 

Response.Write("<asp:" + TypeInformation.Name +

 " runat=\"server\" />
");

 

What you ll get is a list of tags like this:

 

...

 

Then drop the resultant HTML into a skin file and, presto, you have a new template to work with that shows you all the different controls that can be skinned.

 

In this article we ve looked at using themes in a slightly different way. You may feel that localization is a serious abuse of the themes system, but as you already know, rules are there to be broken.

 

The sample code in this article is available for download.

 

VBUG member Phil Winstanley is a highly experienced Web developer who is internationally acclaimed and possesses a burning passion for Internet technologies and solution building, specialising in database-driven Web applications using ASP.NET, C#, SQL Server, and XHTML. Writing is a recent adventure for Phil, who s currently writing some chapters for the Wrox title Professional ADO.NET 2: Programming with SQL Server 2005, Oracle, and MySQL. Phil s been awarded Microsoft MVP status for the past few years and is a member of the ASP Insiders, a group of trusted industry experts who provide early feedback to the Web Platforms team at Microsoft. He also helps to run the MsWebDev online community (http://www.mswebdev.org.uk/). Phil doesn t do VB.NET.

 

 

 

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish