Skins and Themes in ASP.NET

There are many benefits of attending Ivy League schools such as Princeton or MIT. One thing young people get for their money is an opportunity to study under famous computer scientists like Brian Kernighan (Princeton) and Tim Berners-Lee (MIT). If I had a crystal ball, I would have tried harder to earn a scholarship to MIT. (With 14 brothers and sisters it is unlikely my parents ever could have paid the vig on an MIT education.)


Brian Kernighan is credited with inventing the C programming language with Dennis Ritchie although Kernighan says it was all Dennis, and Berners-Lee (not Al Gore) invented the Internet. At its essence the Internet uses the Transfer Control Protocol (TCP) to transmit text; that text is in the form of HTML, a type of hypertext. It is HTML that makes the web more interesting than just a bunch of plain old text. HTML uses tags to convey meaning and link to other content. If you can visualize the millions of pages linked by these tags then the web metaphor makes sense.


When I created my first web page around 1994, its appearance was based on inline information associated each tag. The inline information specified such things as color, font, size, and layout. As I grew more experienced and organized, I started using the style attribute. Unfortunately, style information placed directly in HTML clutters up the HTML document. This cluttered inline-style information has been dubbed “tag soup.” Tag soup is to HTML what spaghetti code is to jumbled VB code.


Over time, the technologies associated with creating web pages have improved. Inline style information can be replaced with a style block, which is a bit of an improvement. More importantly, the adoption of Cascading Style Sheets (CSS) let you describe presentation semantics-style information-in an external style sheet, and apply that style sheet to an entire web site. CSS has been around since the beginnings of Standard Generalized Markup Language (SGML) in the 1970’s. In contrast, CSS for HTML wasn’t formally adopted by the World Wide Web Consortium (W3C) until 1996. (By the Way, Tim Berners-Lee chairs the W3C.)


Skins and themes are a further evolutionary step in defining how a web application will look. Themes give you the ability to customize an application’s appearance by changing the theme rather than the application itself. The terms theme and skin are often used interchangeably, but the differences have to do with scope. A theme is a collection of settings that define how pages and controls look; they act consistently across a web application. A skin is a file with a .skin extension. Skin files contain settings for individual controls such as Buttons and Labels. A theme can contain skins and may also contain images, cascading style sheets, and other resource types.


This article will show you how to define both a custom skin and a theme for a web application.


Adding a Theme to Your Web Application


You can add a custom theme to your web project from the Solution Explorer. Right-click the root project name and click “Add ASP.NET Folder” from the context menu, and then select the Theme item. This step adds an App_Themes folder containing a Theme1 subfolder. The intent is that each theme subfolder should contain all the elements for a particular theme. Therefore, if you want to have multiple themes, simply add additional Theme sub-folders to the App_Themes folder.





Author’s Note: You can also click App_Themes, select Add ASP.NET Folder and pick “Theme” from the context menu after you’ve added the
App_Themes
folder to your project.


Defining a Skin File


Skin files are XML files with a .skin extension. To add a skin file to your web project’s Theme folder, right-click the Theme folder (Theme1 in this example), and select Add New Item. From the Add New Item dialog select the Skin File item.


Visual Studio inserts a skin file template that initially contains a comment and some boilerplate heading information that shows you two examples:

<%–
Default skin template. The following skins are provided as examples only.
1. Named control skin. The SkinId should be uniquely defined because
duplicate SkinId’s per control type are not allowed in the same theme.
<asp:GridView runat=”server” SkinId=”gridviewSkin” BackColor=”White” >
<AlternatingRowStyle BackColor=”Blue” />
</asp:GridView>
2. Default skin. The SkinId is not defined. Only one default
control skin per control type is allowed in the same theme.
<asp:Image runat=”server” ImageUrl=”~/images/image1.jpg” />
–%>


Figure 1. Associating Controls with Skins:
If your skin files contain control properties with a SkinId attribute set, then you can select a specific value for the control’s SkinID property.

The first example in the preceding skin file contains a SkinId, while the second example does not. That’s important, because when a skin element has a SkinId it belongs to the group of items having that same SkinId. However, elements without a SkinId become part of the default Skin definition.


A skin file can contain multiple skins. You can have one default skin-control properties without a SkinId-and as many named skins as you want: control properties with SkinId attributes. If your skin elements have a SkinId then Visual Studio will let you select the various SkinId values from a control’s SkinID property (see Figure 1).


One reasonable way to define control properties for a skin file is to format the item’s appearance directly in an ASP.NET web page-and then copy and paste the applicable elements from the ASPX file to the .skin file. The following code shows the skin file elements defined for the example application:

<asp:GridView runat=”server”
AllowPaging=”true” Font-Names=”Tahoma”
Font-Size=”9pt” CellPadding=”4″>
<HeaderStyle BackColor=”#C1DBFA” />
<AlternatingRowStyle BackColor=”#ECF4FE” />
<RowStyle />
<PagerStyle CssClass=”PagerStyleClass” BackColor=”#C1DBFA” />
</asp:GridView>


Figure 2. Skinned GridView:
Here’s how the GridView looks with a skin file applied.

Notice that the boilerplate comments were removed from the preceding code, which provides HeaderStyle, AlternatingRowStyle, and PagerStyle settings. The skin contents also look very similar to the HTML/XML that defines a GridView in an ASPX page.


These control properties define a default skin. The skin specifies BackColor attributes for the header and alternating rows, and references a cascading style sheet class for the PagerStyle (discussed in more detail in the next section). It’s worth noting that the runat attribute has to be set to server in the .skin file. Figure 2 shows the result when this skin file is applied to a GridView.


Building Out a Cascading Style Sheet


While writing my latest book, I got so used to looking at the Aqua theme provided with the DevExpress controls that I decided to approximate it for the demo. The style employs a subtle contrast between the header and footer and the alternating rows. The preceding skin file defines the control properties, including fonts and colors; however, skin files do not support style information for HTML elements. You need to define those in a cascading style sheet. The good news is that adding a cascading style sheet to your theme automatically incorporates it as part of the theme, without you having to add a specific reference in your web page.


The example in Figure 2 shows a GridView populated with information from the Northwind database’s Customers table. The grid is inside a <div> tag with some padding applied, and the table header <th> and table cell <td> use a solid thin blue border. (Remember that controls such as GridViews are rendered as HTML.) The pager is also rendered as an HTML table, but I didn’t want a border around the pager items. To eliminate the border around the pager items the PagerStyleClass uses a combinatory * and td to indicate that descendant td elements inside of the PagerStyleClass will use the PagerStyleClass settings. Here’s the CSS file added to Theme1:

body {
}
.divClass
{
border:solid thin Silver;
margin: 10px 20px 10px 20px;
padding: 10px 20px 10px 20px;
}
.PagerStyleClass * td
{
border-style: none;
}
th, td
{
border:solid thin #A3C0E8;
}

The .divClass entry defines a border, margin, and padding. This .divClass is assigned to the page’s main <div> tag’s class attribute. The element styles for the th (table header) and td (table cell) define a solid, thin, bluish border. All <th> and <td> elements will employ this style unless it’s overridden by some other style. You could also define a specific style class for the grid using the combinator approach used with the .PagerStyleClass. Finally, the .PagerStyleClass * td uses the combinator * to mean that the style information applies to descendant table cells.


With the theme complete, you can remove all redundant control properties from the ASPX pages to unclutter the ASPX code. You don’t have to do this because theme information overrides local property settings-but doing so may eliminate some confusion. Here’s the ASPX code for the sample solution:

<%@ Page Language=”VB” AutoEventWireup=”false”
CodeFile=”Default.aspx.vb” Inherits=”_Default” %>

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>

<html >
<head runat=”server”>
<title></title>
</head>
<body>
<form id=”form1″ runat=”server”>
<div class=”divClass”>
<asp:GridView ID=”GridView1″ runat=”server” AutoGenerateColumns=”False”
DataKeyNames=”CustomerID” DataSourceID=”SqlDataSource1″>

<Columns>
<asp:BoundField DataField=”CustomerID” HeaderText=”CustomerID” ReadOnly=”True”
SortExpression=”CustomerID” />
<asp:BoundField DataField=”CompanyName” HeaderText=”CompanyName”
SortExpression=”CompanyName” />
<asp:BoundField DataField=”ContactName” HeaderText=”ContactName”
SortExpression=”ContactName” />
<asp:BoundField DataField=”ContactTitle” HeaderText=”ContactTitle”
SortExpression=”ContactTitle” />
<asp:BoundField DataField=”Address” HeaderText=”Address”
SortExpression=”Address” />
<asp:BoundField DataField=”City” HeaderText=”City” SortExpression=”City” />
<asp:BoundField DataField=”Region” HeaderText=”Region”
SortExpression=”Region” />
<asp:BoundField DataField=”PostalCode” HeaderText=”PostalCode”
SortExpression=”PostalCode” />
<asp:BoundField DataField=”Country” HeaderText=”Country”
SortExpression=”Country” />
<asp:BoundField DataField=”Phone” HeaderText=”Phone” SortExpression=”Phone” />
<asp:BoundField DataField=”Fax” HeaderText=”Fax” SortExpression=”Fax” />
</Columns>
<PagerStyle BorderStyle=”None” />
</asp:GridView>
<asp:SqlDataSource ID=”SqlDataSource1″ runat=”server”
ConnectionString=”<%$ ConnectionStrings:NorthwindConnectionString %>”
SelectCommand=”SELECT * FROM [Customers]”></asp:SqlDataSource>
</div>
</form>
</body>
</html>



Adding the Theme to a Web Page


You can apply a theme to an individual web page by adding either a Theme or a StyleSheetTheme attribute to the page’s @Page directive. The following code fragment demonstrates how to use the Theme attribute; you use the StyleSheetTheme attribute in the same way:

<%@ Page Language=”VB” AutoEventWireup=”false”
CodeFile=”Default.aspx.vb” Inherits=”_Default” Theme=”Theme1″%>




Author’s Note: The difference between Theme and StylesheetTheme is that if you apply the Theme attribute then the theme’s control property settings take precedence over any local property settings. In contrast, if you apply the StylesheetTheme attribute, local property settings take precedence over theme-based settings.


Adding a Theme to an Entire Web Application


If you want to apply a theme to your entire web application, then you set the theme attribute of the <pages> tag in the web.config file as shown below:

<pages theme=”Theme1″>

You’ve seen the rudiments of custom themes, skin files, and cascading style sheets, including the subtle yet important difference between the @Page Theme and @Page StylesheetTheme attributes. For some great ideas for defining custom themes, look at some of the pre-defined themes used for other sample projects and existing web sites. You can also check out DevExpress’s ASP.NET controls for good theme ideas. You can download trial versions at http://www.devexpress.com.


About the Author


Paul Kimmel is the VB Today columnist for www.codeguru.com. He has written several books on object-oriented programming and .NET. Check out his latest book Professional DevExpress ASP.NET Controls (from Wiley), and watch for his upcoming book Teach Yourself the ADO.NET Entity Framework in 24 Hours (from Sams). Paul is also a Technical Evangelist for Developer Express, Inc. You can ask him about Developer Express or read his DX blog here.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read