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.)
initArticleMenu(document.getElementById("toolBoxShareMenu"));
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="http://www.stableflow.com/images/image1.jpg" />
--%>
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>
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 xmlns="http://www.w3.org/1999/xhtml">
<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.
Original article