Themes and Skins

A theme is a collection of property settings used to define the visual appearance of pages and their controls for consistency across the pages of a Web site. A theme can be applied to an entire Web site, to a single page and its controls, or to an individual control. There is similarity to applying Cascading Style Sheets, with the addition of control properties for which there are no CSS equivalents. Figure 12-35 shows selected controls to which theming is applied to those in the left column.

Themed Control No Themed Control
Themed Label control No Themed Label control
Themed HyperLink No Themed HyperLink
Themed LinkButton No Themed LinkButton




Themed GridView
BookTitleBookPrice
Oracle Database$69.99
Databases in Depth$29.95
Database Processing$136.65
Access Database Design$34.95
SQL Server 2005$29.99
No Themed GridView
BookTitleBookPrice
Oracle Database$69.99
Databases in Depth$29.95
Database Processing$136.65
Access Database Design$34.95
SQL Server 2005$29.99
Themed DetailsView
Title: Oracle Database
Price: $69.99
12345
No Themed DetailsView
Title: Oracle Database
Price: $69.99
12345
Figure 12-35. Applying Themes to server controls.

The Themes Directory

Themes are collected in a special app_Themes directory that appears in the root directory (the virtual directory) of a Web site. You must create this directory with this name irrespective of whether a theme is applied to the entire site or to one particular control on one particular page of the site.

Inside the app_Themes directory are one or more subdirectories containing different styling themes that can be applied to the site. Only one subdirectory needs to be created if only one theme is applied. This subdirectory can have any name. For example, the theme applied in the above example is contained inside the app_Themes\ASPTheme1 directory of this tutorial site.

Skin Files

A theme is a collection of styled controls packaged as text files with the special extension .skin. Any control to be styled can be described in its own skin file. The file contains coding for a control with property settings describing a model to follow in styling this type of control. For example, the following Button.skin file appears in the ASPTheme1 subdirectory to define styling for an <asp:Button> control. This styling is applied to the themed Button appearing in Figure 12-35.

<asp:Button SkinID="ASPButton" Runat="Server"
  Font-Name="Comic Sans MS"
  Font-Size="10pt"
  Font-Bold="True"
  BackColor="#990000"
  ForeColor="#FFFFFF"
  BorderStyle="Outset"
  BorderWidth="3"/>
Figure 12-36. A Button.skin file for a Button control.

The themed control includes only those property settings that are shared among all such controls that adopt this skin. Individual controls may have properties that are unique to themselves and are not included in the skin. Incidentally, the file name Button.skin is not significant. Any valid file name can be used as long as it has the .skin extension.

Named Skins

There are two categories of skins that can be created. A named skin is assigned a SkinID, as in the above example. A named skin is adopted by individual controls by refering to this SkinID. For instance, a Button control takes on the appearance of the button described in the Button.skin file by including the following SkinID reference.

<asp:Button Text="Themed Button" SkinID="ASPButton" Runat="Server"/>
Listing 12-35. Adopting a Button skin through a SkinID reference.

Other buttons on the page do not take on this appearance if they do not include this SkinID reference.

Default Skins

A default skin does not have a SkinID. It becomes the skin for all such controls on any page that applies the theme of which this skin is a part.

<asp:Button Runat="Server"
  Font-Name="Comic Sans MS"
  Font-Size="10pt"
  Font-Bold="True"
  BackColor="#990000"
  ForeColor="#FFFFFF"
  BorderStyle="Outset"
  BorderWidth="3"/>
Figure 12-37. A default Button.skin file for a Button control.

In this rewrite of the Button.skin file, the control is not labeled with a SkinID. Therefore, this styling applies to all <asp:Button> controls on a page that adopts theming.

A Collective Skins File

As mentioned, it is common to code a skin for a control type in its own separate .skin file. However, all skins can be packaged in a single .skin file. In the following illustration, all skins that comprise a theme are coded in a single file rather than as separate skin files.

<asp:Button SkinID="ASPButton" Runat="Server"
  Font-Name="Comic Sans MS"
  Font-Size="10pt"
  Font-Bold="True"
  BackColor="#990000"
  ForeColor="#FFFFFF"
  BorderStyle="Outset"
  BorderWidth="3"/>

<asp:Label SkinID="ASPLabel" Runat="Server"
  BackColor="#F0F0F0"
  ForeColor="#990000"
  BorderStyle="Ridge"
  BorderWidth="3"
  Style="padding:3px"/>

<asp:HyperLink SkinID="ASPHyperLink" Runat="Server"
  Font-Name="Comic Sans Ms"
  Font-Size="12pt"
  BackColor="#FFFFFF"
  ForeColor="#990000"/>

<asp:LinkButton SkinID="ASPLinkButton" Runat="Server"
  Font-Name="Comic Sans Ms"
  Font-Size="12pt"
  BackColor="#FFFFFF"
  ForeColor="#990000"/>

<asp:TextBox SkinID="ASPTextBox" Runat="Server"
  Width="200"
  Height="27"
  BackColor="#F0F0F0"
  ForeColor="#990000"
  BorderStyle="Inset"
  BorderWidth="3"
  Style="padding:3px"/>

<asp:RadioButtonList SkinID="ASPRadioButtonList" Runat="Server"
  Font-Bold="True"
  BackColor="#E0E0E0"
  ForeColor="#990000"
  BorderStyle="Solid"
  BorderWidth="1"
  BorderColor="#990000"/>

<asp:DropDownList SkinID="ASPDropDownList" Runat="Server"
  Font-Name="Comic Sans Ms"
  BackColor="#E0E0E0"
  ForeColor="#990000"/>

<asp:GridView SkinID="ASPGridView" Runat="Server"
  CellPadding="2"
  BorderStyle="Ridge"
  BorderWidth="5"
  BackColor="#F0F0F0"
  ForeColor="#990000"
  HeaderStyle-BackColor="#990000"
  HeaderStyle-ForeColor="#FFFFFF"
  AlternatingRowStyle-BackColor="#C07777"
  AlternatingRowStyle-ForeColor="#FFFFFF"/>

<asp:DetailsView SkidID="ASPDetailsView" Runat="Server"
  AllowPaging="True"
  CaptionAlign="Left"
  CellPadding="2"
  BorderStyle="Ridge"
  BorderWidth="5"
  BackColor="#F0F0F0"
  ForeColor="#990000"
  HeaderStyle-BackColor="#990000"
  HeaderStyle-ForeColor="#FFFFFF"
  AlternatingRowStyle-BackColor="#C07777"
  AlternatingRowStyle-ForeColor="#FFFFFF"
  PagerStyle-BackColor="#E0E0E0"/>
Figure 12-38. Contents of Controls.skin file.

Again, the name of the .skin file is not important. Skin definitions are applied individually through their SkinID references, or they are applied to all such controls by not coding a SkinID in the skin file.

Applying Themes

Themes and their skins can be applied to an entire Web site (application level) or to selected pages (page level). To apply a theme at the application level, the web.config file in the site's root directory is modified to include a <pages> element giving the name of the theme to apply, that is, the name of the subdirectory of the app_Themes directory containing applicable .skin files. For example, the theme folder named ASPTheme1 is applied to an entire site with the following web.config setup.

<configuration>
  <system.web>
    <pages theme="ASPTheme1"/>
  </system.web>
</configuration>
Figure 12-39. Contents of web.config file to apply a theme to a site.

In this case, any control on any page can take part in this theme by including the SkinID of a control described in a .skin file in the ASPTheme1 directory. If a control's skin does not have a SkinID assigned, then the skin is applied to all such controls on all pages of the site.

An alternative to applying a theme site-wide is to apply it to individual pages. A page takes part in a theme by setting the Theme attribute in the page's <@ Page> directive.

<@ Page Language="vb" Debug="True" Theme="ASPTheme1" %>
Listing 12-36. Page directive to apply a theme to a page.

Again, any control on the page can adopt a theme by referencing the SkinID of a control described in one of the named directory's .skin files. If a control's skin does not have a SkinID assigned, then the skin is applied to all such controls on that page.

Coding a Theme attribute in the page directive on all pages of a site is the equivalent of including a <pages> element in the web.config file. Either technique can be used, although changing themes is easier if coded once in the web.config file.

Themes and Style Sheets

A standard CSS stylesheet can be part of a theme. This is necessary where common styling beyond those properties defined in control skins is applied. To include a style sheet as part of a theme, create a text file with a .css extension and code style settings in the same manner as you would for any linked style sheet. Make sure the file is saved to your themes folder along with its companion .skin files. Now, the style sheet is applied to all pages to which the theme is applied.

Themes are equivalent to CSS style sheets, at least for those theme properties that have CSS equivalents. You may, in fact, have skin properties and CSS styles that both apply to the same control. Where there is an equivalent property and style, the theme takes precedence. For example, the following skin and style sheet entries all pertain to the same Button control and all specify conflicting styles.

Button Skin Button Style Sheet
<asp:Button SkinID="MyButtonSkin"
  BackColor="Red" ForeColor="White"
  .../>
<style type="text/css">
#MyButton {background-color:blue;
           color:yellow}

</style>
Styled Button
<asp:Button id="MyButton" SkinID="MyButtonSkin" Runat="Server"
  style="background-color:green; color:black"/>
Figure 12-40. Application of multiple styles to a button.

If a Theme="theme" attribute is applied to a page in a <@ Page> directive, or if a <pages theme="theme"/> entry appears in a web.config file, then the skin setting is applied exclusively. Unlike working with standard style sheets, theme-related style sheets do not cascade. Only the theme is applied.

If, however, the desire is to share control styling with style sheets, then the Theme attribute must be replaced by a StyleSheetTheme="theme" attribute in the <@ Page> directive, or <pages stylesheettheme="theme"/> is coded in the web.config file. In this case, theme styling is overridden by style sheet styles, with CSS styles taking precedence.

Setting Themes Programmatically

Rather than setting a theme declaratively—in a <@ Page> directive or in the web.config file—you can apply it dynamically through a script. So that the theme is applied prior to a page being loaded, it must take place during the page.preinit event, that is, before the page-load process is "initiated." This means that setting the page's theme must take place in a Page_PreInit subprogram.

Sub Page_PreInit

  Page.Theme = "ASPTheme1"

End Sub
Listing 12-37. Setting a page theme during page-load initiation.

The name of the theme to apply to the page is, of course, the name of a theme directory containing the skins and style sheets to apply. When this technique is used, it is not necessary to include a theme setting in the <@ Page> directive or in the web.config file unless it represents a default scheme that is overridden by the scripted theme.

The following buttons alternate between two different themes that can be applied to this page. The "ASPTheme1" button applies the theme from directory ASPTheme1 when this page opens. The "ASPTheme2" button applies a different theme from directory ASPTheme2. Click the buttons and scroll to Figure 12-35 to view the two themes, which the buttons themselves take on as well.

Code for these two buttons along with the Page_PreInit script to set this page's theme is shown below. Notice that the buttons are assigned SkinIDs so that they take on the alternate themes they represent.

Sub Page_PreInit

  If Request.QueryString("Theme") <> "" Then
    Page.Theme = Request.QueryString("Theme")
  Else
    Page.Theme = "ASPTheme1"
  End If

End Sub

<asp:Button Text="ASPTheme1" SkinID="ASPButton" Runat="Server"
  PostBackUrl="aspnet12-08.aspx?Theme=ASPTheme1"/>
<asp:Button Text="ASPTheme2" SkinID="ASPButton" Runat="Server"
  PostBackUrl="aspnet12-08.aspx?Theme=ASPTheme2"/>
Listing 12-38. Code to alternate page themes.

Shown below are the two skins for <asp:Button> controls appearing in the two themes. Comparable styling differences appear for the other controls in Figure 12-35.

ASPTheme1 Button Skin ASPTheme2 Button Skin
<asp:Button SkinID="ASPButton" 
Runat="Server"
  Font-Name="Comic Sans MS"
  Font-Size="10pt"
  Font-Bold="True"
  BackColor="#990000"
  ForeColor="#FFFFFF"
  BorderStyle="Outset"
  BorderWidth="3"/>
	
<asp:Button SkinID="ASPButton" 
Runat="Server"
  Font-Name="Verdana"
  Font-Size="8pt"
  Font-Bold="True"
  BackColor="LightSkyBlue"
  ForeColor="Navy"
  BorderStyle="Outset"
  BorderWidth="3"
  Height="27"/>
	
Figure 12-41. ASPTheme1 and ASPTheme2 button skins.

Posting to Pages

The previous buttons cannot use standard OnClick event handlers to call the Page_PreInit subprogram because these controls do not exist until after the page is loaded. By that time it is too late to set a theme for the page. For theme choices to be available prior to page loading, they are packaged as query strings appended to the URL for this page and issued through the button's PostBackUrl property.

A button's normal purpose is to call a subprogram. However, it can be configured for general post-back to a page without identifying a subprogram. The PostBackUrl property supplies a relative or absolute URL for a page to which post-back is made. Then, one of the special page subprograms—Page_Load, Page_Init, or Page_PreInit—can handle post-back processing. In this example, the Page_PreInit subprogram handles processing of the posted-back query string.

A test is made for a query string value since, other than arriving by the button click, no other navigations to this page are accompanied by a query string. When arriving at this page through navigation links with no query string is attached, the ASPTheme1 theme is applied. When a button is clicked, however, a query string is available to this page and its named theme is applied to the page's Page.Theme property.

Incidentally, besides a Button control, ImageButtons and LinkButtons also support the PostBackUrl property. They can be used not only to call subprograms through their OnClick and OnCommand event handlers, but can be configured to post information to the same or to a different page, optionally including a query string to identify passed values.