WindowsDevCenter.com
oreilly.comSafari Books Online.Conferences.

advertisement


AddThis Social Bookmark Button Liberty on Whidbey

Skins and Themes

by Jesse Liberty
11/15/2004

In my previous column I showed how to build on web forms security to create a personalized site. In this column, I'll build on that work to introduce the concepts of skins and themes to allow the you to configure the look and feel of your site. If you want to start with a clean version of the personalized pattern, please download the starter kit.

A skin describes how a control should look. A skin can define stylesheet attributes, images, colors and so forth.

A theme is a collection of skins. Having multiple themes allows your users to choose the look of your site by switching from one set of skins to another at the touch of a button. Combined with personalization, your site can remember the look and feel your user prefers.

Two Types Of Themes

There are two types of themes. Stylesheet themes define styles that may be overridden by the page or control. These are, essentially, equivalent to CSS stylesheets. The second type, called customization themes, cannot be overridden. You set a stylesheet theme by using the StyleSheetTheme attribute in the page directive, and, similarly, you set a customization theme by setting the Theme attribute in the page directive.

The Order of Setting Properties

In any given page, the properties for the controls are set in this order:

  1. Properties are applied first from a stylesheet theme.
  2. Properties are then overridden based on properties set in the control.
  3. Properties are then overridden based on a customization theme.

Thus, the customization theme is guaranteed the final word on the look and feel of the control.

Two Types Of Skins

Skins themselves come in two flavors: default skins and explicitly named skins. Thus, you might create a Labels skin file with this declaration:


  <asp:Label runat="server" 
  ForeColor="Blue" Font-Size="Large" 
  Font-Bold="True" Font-Italic="True" />

This is a default skin for all label controls. However, you might decide that some labels must be red. To accomplish this, you create a second skin, but you give this skin a SkinID.


  <asp:Label runat="server" SkinID="RedLabel"
  ForeColor="Red" Font-Size="Large" 
  Font-Bold="True" Font-Italic="True" />

Any label that does not have a SkinID attribute will get the default skin, and any label that sets SkinID="RedLabel" will get your named skin.

To see how skins and themes work, let's return to the Default.aspx page and add a few controls, as shown in Figure 1 and the listing that follows.

Figure 1
Figure 1. Themes in Visual Studio .NET (Whidbey). Click image for full-size screen shot.


<table width ="100%">
  <tr>
    <td >
      <asp:HyperLink ID="linkProfile" Runat="server" 
           NavigateUrl="~/ProfileInfo.aspx">Profile Info
      </asp:HyperLink>
    </td>
    <td >
      <asp:ListBox ID="lbBooks" Runat="server" /> 
    </td>
  </tr>
  <tr>
    <td >
      <asp:Label ID="lblListBox" Runat="server" Text="ListBox"/>
      </td>
    <td >        
      <asp:ListBox ID="lbItems" Runat="server">
        <asp:ListItem>First Item</asp:ListItem>
        <asp:ListItem>Second Item</asp:ListItem>
        <asp:ListItem>Third Item</asp:ListItem>
        <asp:ListItem>Fourth Item</asp:ListItem>
      </asp:ListBox>
    </td>
    <td >
      <asp:Label ID="lblRadioButtonList" Runat="server" 
           Text="Radio Button List"/> </td>
    <td >        
      <asp:RadioButtonList ID="RadioButtonList1" Runat="server">
        <asp:ListItem>Radio Button 1</asp:ListItem>
        <asp:ListItem>Radio Button 2</asp:ListItem>
        <asp:ListItem>Radio Button 3</asp:ListItem>
        <asp:ListItem>Radio Button 4</asp:ListItem>
        <asp:ListItem>Radio Button 5</asp:ListItem>
        <asp:ListItem>Radio Button 6</asp:ListItem>
      </asp:RadioButtonList><br />     
    </td>
  </tr>    
  <tr>
    <td>
      <asp:Label ID="lblCalendar" Runat="server" Text="Calendar">
      </asp:Label>
    </td>
    <td>
      <asp:Calendar ID="Calendar1" Runat="server" />
    </td>
    <td>
      <asp:Label ID="lblTextBox" Runat="server" Text="TextBox"/>
    </td>
    <td>
      <asp:TextBox ID="TextBox1" Runat="server"/>
    </td>
  </tr>
</table>

Related Reading

ASP.NET Cookbook
The Ultimate ASP.NET Code Sourcebook
By Michael A. Kittel, Geoffrey T. LeBlond

With these controls in place, you are ready to add skins.

Organizing Themes and Skins

Themes are stored in your project in a folder named Themes. Under the Themes folder, you'll want to create a folder for each of the themes you'll be creating. For this example, I'll create two folders, one named Dark Blue and one named Psychedelic. Within these folders, I'll place the skins for these different themes.

Skins may be saved all in a single file or they may be divided into various folders. I'll divide my folders by control type. Thus, each Theme folder will have the following files within it

  • Button.skin
  • Calendar.skin
  • Label.skin
  • ListBox.skin
  • RadioBox.skin
  • Text.skin

Each .skin file is just a text file that contains a definition for the control type, but with no ID. Thus, for example, my Label.skin file might look like this (for the Dark Blue theme)


<asp:Label Runat="server" 
ForeColor="Blue" Font-Size="Large" 
Font-Bold="True" Font-Italic="True" />

This defines the default skin for the theme within which I've placed it, as shown in Figure 2.

Figure 2

Figure 2.

Setting SkinIDs

It turns out that even within this theme, I'd like to allow some labels to be red. I can accomplish this by defining a named skin, which I do by providing my alternative skin with a SkinID attribute:


<asp:Label Runat="server" SkinID="Red"
ForeColor="Red" Font-Size="Large" 
Font-Bold="True" Font-Italic="True" />

Notice that this new skin is identical to the label skin defined above except that it bears the SkinID "Red" (and the ForeColor is set to Red). Any page using the Deep Blue theme will set its labels to Blue, unless the label explicitly dictates that it should use the SkinID of Red:


<asp:Label ID="lblRadioButtonList" Runat="server" Text="Radio Buttons" SkinID="Red"/>

The lblRadioButtonList label will be red, because the label explicitly calls for the Red SkinID, as shown in Figure 3.

Figure 3
Figure 3. Click image for full-size screen shot.

Notice that all of the labels in Figure 2 are blue, except for radio buttons, which are red. Similarly, the ListBox skin has both a default and a red skin:


<asp:ListBox Runat="server" 
ForeColor="#FFFF80" Font-Bold="True" 
BackColor="Blue"/>

<asp:ListBox Runat="server" SkinID="Red"
ForeColor="Blue" Font-Bold="True" 
BackColor="Red"/>

and the book's list box has been set to use the SkinID of Red:


<asp:ListBox ID="lbBooks" Runat="server" SkinID="Red" />

Setting Themes

You can set the themes on your page either declaratively or programmatically. To set a theme declaratively, simply add the Theme attribute to the Page directive:


<%@ Page Language="C#" CompileWith="Default.aspx.cs" 
ClassName="Default_aspx" Theme="SmokeAndGlass" %>

This will set the page's theme to the SmokeAndGlass theme.

You can also set the theme programmatically, either by hard coding it, or (even better) by setting it from the user's profile.

Stylesheet themes are set by overriding the StyleSheetTheme property for the page:


public override string StyleSheetTheme
{
  get
  {
    if ( Profile.IsAnonymous == false && Profile.Theme != null )
      return Profile.Theme;
    else
      return "Dark Blue";
  }
  
  set
  {
    Profile.Theme = value;
  }
}

If you are going to set a customization theme programmatically, however, you must do so from the new PreInit event handler for the page, because the theme must be set before the controls are created.


public void Page_PreInit(object sender, EventArgs e)
{
  if ( Profile.IsAnonymous == false )
    Page.Theme = Profile.Theme;
}

This presents a bit of a difficulty when you want to allow the user to change the theme at run time. If you create a control that posts the page back with a new theme, the PreInit code runs before the event handler for your button that changes the theme, and so by the time the theme is changed, the buttons have already been drawn. To overcome this you must, unfortunately, refresh the page again. An alternative is to post to another page, set the theme on the second page, and then come back to the page on which the theme will be reflected. For simplicity, in this example, we'll just click the button (Dark Blue or Psychedelic) twice, thus reposting and drawing the page properly. If you click Psychedelic twice, your profile and the page's theme is set to the (horrific) colors of the Psychedelic theme, as shown in Figure 4:

Figure 4
Figure 4. Themes aren't always pretty. Click image for full-size screen shot.

Default Themes

You can provide a default theme for anonymous users by setting the Theme attribute for the page, and then, on Page_PreInit, check to see if the user has a profile. If so, you then get the user's thematic preference from his profile (don't forget to modify Web.config to add the Theme property).

Jesse Liberty is a senior program manager for Microsoft Silverlight where he is responsible for the creation of tutorials, videos and other content to facilitate the learning and use of Silverlight. Jesse is well known in the industry in part because of his many bestselling books, including O'Reilly Media's Programming .NET 3.5, Programming C# 3.0, Learning ASP.NET with AJAX and the soon to be published Programming Silverlight.


Read more Liberty on Whidbey columns.

Return to ONDOTnet.com