Using Themes to Personalize Your Site


The profiles feature you have seen in this chapter provides a simple way to store information specific to each user, and to persist this information between visits. You saw how you could also use this feature to change the visual appearance of a site by, for example, changing the stylesheet depending on a user's profile information. In the example, this simply changed the size of the text in the page, but it can have a much more pronounced effect on the appearance of the pages.

Such an effect is becoming more important as users increasingly encounter applications that offer a customized "look and feel." The problem is that it takes a great deal of work to design the appearance you want, and to then implement it in each page and for each control or visual feature. Instead, in ASP.NET, you can use a new feature called themes that provides a way to customize the look and feel of your site, including graphics, CSS styles, properties, and so on.

Not only does this provide a way for you, the developer, to provide a consistent style, but it also allows the users to select the style. While this may not be required in every Web site, using themes does allow for consistency among pages and controls, and provides an easy way to change the look of the site.

Incorporating themes requires very few changes to the ASP.NET pages, because themes are stored external to the pages themselves. This means that, from the development perspective, the work involved is minimal. Once theme support is included in a site or a page, the addition, change, or removal of themes is simple. Alternatively, you can disable and prevent the use of themes at both the page and the control level, if required.

What Are Themes and Skins?

The themes feature uses two distinct terms to refer to its components:

  • A skin is the visual style applied to an individual control, usually as a set of stylesheet attributes, images, colors, and so on.

  • A theme is a collection of skins, and applies to an ASP.NET page rather than an individual control.

Each theme can have a default look that does not specify a skin, or there can be multiple skins within each theme. This means you can have a theme that itself provides differing appearances; for example, a theme called Pastel may have within it skins called Pink and Blue.

A theme does not have to provide a skin for every server control. Controls that do not have a skin defined within the theme file will have the default appearance that depends on the usual features such as the browser and stylesheet in use. For consistency, however, it looks better if you provide a skin for every control you use.

Default and Named Skins

A unique SkinID property can optionally identify each skin in a theme. This allows you to define multiple skins for the same control within one theme, as long as they have different SkinID values.

Within a theme file, skins that contain a SkinID are called named skins and are not applied automatically to controls of that type. You must apply these skins specifically to controls on the page by setting their SkinID property to that of the skin. Bear in mind, however, that an exception is raised if the specified skin cannot be found at runtime.

Skins that do not have a SkinID property are called default skins, and ASP.NET automatically applies these to controls of the matching type when the theme is set for the page.

Global Themes and Page Themes

The themes for a single Web site are stored within the App_Themes subfolder of the application root folder, with each theme in a separate folder. Within each theme folder is the .skin file that implements the theme and contains the skin details for each control, any CSS stylesheets required by the theme, and any images required for controls (for example, the expand/contract images for the TReeView control). Figure 12.9 shows the structure of three themes (provided with the examples for this book) as they appear in the App_Themes subfolder in Visual Studio.

Figure 12.9. The structure of a theme in the App_Themes subfolder


Themes defined like this within the Web site App_Themes subfolder are called page themes, and they only apply to that site. Alternatively, you can create global themes that are available to any Web site on the machine. You simply place the complete theme files folder structure within the aspnet_client\system_web\[version]\Themes folder of your default Web site directory. For example, in version 2.0 where your default Web site is on drive C, you would place the files in the folder:

C:\Inetpub\wwwroot\aspnet_client\system_web\2_0_50727\Themes\


There are no themes provided with ASP.NET. However, it is likely that packs of themes will be available as add-ons to the Framework, and you will find sample themes created by other developers available on the Web. Try http://www.dotnettreats.com/samplethemes/, or search for "download ASP.NET themes".


Creating Themes and Skins

Simple theming of controls requires only a declaration of that control in the .skin file, just as you would declare the control in an ASP.NET page but omitting the ID attribute. Listing 12.17 shows a simple skin definition for the TextBox control, taken from the example "Smoke and Glass" theme.

Listing 12.17. The Skin Definition for a Textbox in the Smoke and Glass Theme

<asp:TextBox runat="server"      BackColor="#FFFFFF" ForeColor="#585880"      BorderStyle="Solid" BorderWidth="1pt" BorderColor="#585880"      Font-Size="0.9em" Font-Names="Verdana" />

Using CSS Stylesheets in a Theme

You can include a CSS stylesheet in your theme, as well as a .skin file, and use the selectors it contains to add styles to the controls and the page to which you apply the theme. The declarations in the stylesheet are exactly the same as a stylesheet you would specify using a <link> element in your pages, and can contain element-specific selectors that apply to the page as a whole as well as named selectors that you apply individually to controls. For example, your stylesheet can contain a declaration that sets the body text appearance like this:

body {font-family:Verdana,Arial,Helvetica,sans-serif;       font-size:.9 em; line-height:110%; color:#35354D;}


It can also include named selectors, such as this one that specifies an image included in the images folder of the theme as the background of the elements to which this selector is specifically applied:

.theme_header {background-image :url(images/fade.gif);}


Using Images in a Theme

As well as specifying images included in a theme for the background of controls, such as you just saw in a CSS stylesheet, you can use them directly in properties of the control skin declarations. For example, Listing 12.18 shows the declaration of the skin for the BulletedList control in the "Smoke and Glass" sample theme. You can see that the BulletImageUrl property is set to an image within the themes folders (using a relative path based on the location of the .skin file), and the BulletStyle is "CustomImage". This causes any BulletedList control on a themed page to use the specified image for the bullets in the list.

Listing 12.18. The Skin Definition for a BulletedList in the Smoke and Glass Theme

<asp:BulletedList runat="server"      Font-Names="Verdana"      BulletImageUrl="images/smokeandglass_bullet2.gif"      BulletStyle="CustomImage"      BackColor="transparent" ForeColor="#585880" />

As another example, Listing 12.19 shows the declaration of the GridView control skin in the "Smoke and Glass" theme. Here, you can see how the properties for each section of the grid are set to match the theme, and that some (such as the HeaderStyle, SelectedRowStyle, EditRowStyle, and FooterStyle sections) use named style selectors to specify the CSS style to apply to that section.

Listing 12.19. The Skin Definition for a GridView in the Smoke and Glass Theme

<asp:GridView runat="server"      ForeColor="#585880" CellPadding="5" GridLines="None"      BorderStyle="Double" BorderColor="#E7E5DB" BorderWidth="2pt"      Font-Size=".9em" Font-Names="Verdana"   <HeaderStyle ForeColor="#585880" BorderColor="#CCCCCC"      BorderWidth="1pt" Css />   <RowStyle ForeColor="#585880" BackColor="#FFFFFF" />   <AlternatingRowStyle ForeColor="#585880" BackColor="#F8F7F4" / >   <SelectedRowStyle ForeColor="#585880" BorderStyle="solid"      BorderWidth="2pt" BorderColor="585880"      Css />   <EditRowStyle ForeColor="#585880" Font-Bold="True"      BorderWidth="1pt" BorderStyle="Solid"      Css />   <PagerStyle ForeColor="#585880" BackColor="#E7E5DB" />   <FooterStyle ForeColor="#585880" Css /> </asp:GridView>

Figure 12.10 shows the result of the three control declarations in Listing 12.17, Listing 12.18, and Listing 12.19, including the effects of the CSS styles defined in the stylesheet that is part of this theme.

Figure 12.10. The effects of the Smoke and Glass example theme


One way to create a set of skins for a theme is to build a page containing the controls you want to generate skins for and style them as required by setting their properties. Then copy the control declarations into your .skin file and remove the control ID attributes. Remember that you can only have one default skin for each type of control in your .skin file. If you need more than one skin for a specific control type, you must create named skins by adding a unique SkinID attribute to all except the default skin declaration.

Note that themes only apply to controls from the System.Web.UI.WebControls namespace and associated namespaces such as System.Web.UI.WebControls.WebParts.


Applying Themes and Skins

After creating and/or installing your themes, you can apply them to your pages and controls in the following ways, depending on whether you want to apply them at design time or runtime, and the scope that you want them to have:

  • Use the <pages> section of the web.config file to specify the theme that applies to a complete site or section of a site.

  • Use the @Page directive in the pages to which the theme will apply.

  • Apply a theme to a complete page dynamically at runtime.

  • Apply a theme to a complete site or set of folders dynamically at runtime.

  • Apply a specific named skin to controls on the page at design time or runtime.

  • Apply a theme so that it does not override the style and property settings on a control.

The following sections describe these options.

Applying a Theme at Design Time

You can set the theme for all the pages in a site or a subfolder of a site in the <pages> element of the <system.web> section of web.config. All pages in this folder and its subfolders will use the specified theme, unless overridden by another web.config file that specifies a different theme:

<system.web>   <pages theme="SmokeAndGlass" ... /> </system.web>


To apply a theme to a specific page, you can declare it in the @Page directive:

<%@ page Language= "c#" Theme= "SmokeAndGlass" %>


You cannot declare a theme in a master page, though you can do so in the @Page directive of a content page.

Applying a Theme Dynamically at Runtime

If you want to apply a theme at runtime, you must do so in the Page_PreInit event handler for the page. You cannot use the Page_Load event handler, because at this stage ASP.NET has already set the properties for the controls in the page. Listing 12.20 shows a Page_PreInit event handler that sets the theme for the page to the "Smoke and Glass" theme as the page is executing.

Listing 12.20. Setting the Theme for a Page at Runtime

protected void Page_PreInit(Object sender, EventArgs e) {   Page.Theme = "SmokeAndGlass"; }

One problem with this approach is that you cannot change the theme in response to a postback in the usual way, because the values of the controls in the page are not available in the PreInit event. However, you can extract a value directly from the Request collections (Form or QueryString) in the PreInit event handler and use these to set the theme for the page.

An alternative approach is to apply the theme centrally at runtime using an HTTP handler module. You will see this approach in the example toward the end of this chapter, in the section Using an HTTP Module to Set the Theme, where the theme set depends on a value in the user's profile.

Applying a Named Theme at Design Time or Runtime

To apply a named theme to a control, you specify the SkinID of the skin as the SkinID property or attribute of the control. For example, to set the theme for a Textbox to the skin with SkinID "MyTextboxSkin", you would declare the Textbox control as:

<asp:Textbox runat=server Skin ... />


All other Textbox controls on the page that do not specify a SkinID property will use the default theme skin (if a theme applies to the page). To set the SkinID dynamically, you must do so in the Page_PreInit event (see Listing 12.21)as you do when setting the theme for a page dynamically.

Listing 12.21. Setting the SkinID of a Control at Runtime

protected void Page_PreInit(Object sender, EventArgs e) {   ThisTextbox.SkinID = "MyTextboxSkin"; }

Applying a Theme that Does Not Override Existing Styles and Property Values

By default, when you apply a theme using the Theme property of a page, in web.config, in the @Page directive, or by specifying a SkinID property on a control, the styles in the theme override the settings on the controls so that the theme can provide a consistent appearance over all the controls. If a control defines a property value also defined by the theme, the theme's value overrides the control's property setting.

Themes declared in a @Page directive, or set as the Theme property of a page at runtime, override any conflicting values set in a web.config file. Likewise, any settings in a skin specifically applied using the SkinID property override all other conflicting theme property values.

However, you can apply a theme in such as way that it does not override the existing properties and settings of the controls on a page. To achieve this, set the StyleSheetTheme property instead of the Theme property of the page, either dynamically at runtime or in the @Page directive:

<@Page Language="C#" StyleSheetTheme="SmokeAndGlass" ... />


If you want to set the StyleSheetTheme of a page dynamically at runtime, you must override the StyeSheetTheme property, as shown in Listing 12.22. You can access the Request collections to extract the required theme name, if required.

Listing 12.22. Setting the StylesheetTheme Property of a Page at Runtime

public override String StyleSheetTheme {   get { return "SmokeAndGlass"; } }

Preventing the Use of Themes and Skins

Themes are not applied to pages or controls that contain the EnableTheming="False" attribute, or which set the EnableTheming property to false. This means that you can set the theme for a page or a complete site and then prevent individual controls from using the theme.

If you build custom controls, you can prevent theming of the complete control, or just specific properties, using attributes in the class file that implements the control. To prevent a control or a property of the control from being themed, add the [Themable(false)] attribute to the class or member declaration. Listing 12.23 shows how this attribute can be applied to both the control class and a property of the class. Of course, if the control itself prevents theming, then you do not need the attribute on the individual members of the control.

Listing 12.23. Preventing Theming of a Customer Control with the Themable Attribute

[Themable(false)] public class MyCustomControl : System.Web.UI.WebControl {   [Themable(false)]   public String MyCustomProperty   {     get {...}     set {...}   }   ... }

An Example of Using Themes

As an example of how you can use themes, the membership and profiles example you saw in the previous chapter and earlier in this chapter also allows visitors to specify a theme for the site, and it persists this theme in their user profile. The Shopping Cart page in this version of the example contains an extra drop-down list that allows the selection of one of three themes, or "-none-" to remove the current theme. Figure 12.11 shows the page with the "Smoke and Glass" theme applied.

Figure 12.11. The Shopping Cart page with a theme applied


To achieve this, the first step is to add a property to the profile, in the <properties> section of the <profile> element in web.config (see Listing 12.24). Notice that this is an anonymous profile property, so that visitors can specify their preferred theme without having to log in first.

Listing 12.24. Adding the Profile Property for the User's Selected Theme

<profile enabled="true" defaultProvider="Sql2005ProfileProvider">   <properties>     ...     <add name="PageTheme" allowAnonymous="true" />   </properties> </profile>

Next, a DropDownList control on the page allows visitors to select a theme (see Listing 12.25). The value "-none-" allows the user to remove the current theme.

Listing 12.25. A Drop-Down List for Selecting a Theme

<asp:DropDownList  runat="server">   <asp:ListItem Text="-none-" />   <asp:ListItem Text="BasicBlue" />   <asp:ListItem Text="SmokeAndGlass" />   <asp:ListItem Text="UglyRed" /> </asp:DropDownList>

Saving and Loading the Theme Profile Value

The code in the page must save the value selected in the drop-down list in the visitor's profile, and must extract it when the page loads to select the appropriate entry in the drop-down list. In the ShowProfileValues routine, which displays the visitor's profile values in the page, this extra line of code sets the drop-down list to the value stored in his or her profile. If there is no value stored there, it remains set to the first item "-none-":

lstPageTheme.SelectedValue = Profile.PageTheme;


In the UpdateProfileValues routine, which runs when a visitor clicks the Update button to save his or her profile settings, this line of code saves the selected theme name (or "-none-") in their profile:

Profile.PageTheme = lstPageTheme.SelectedValue;


Then it is just a matter of setting the Theme property of the page to the theme value stored in the current visitor's profile. As you saw earlier in this chapter, you can only do this in the Page_PreInit event. Listing 12.26 shows the code for the Page_PreInit event handler. This extracts the name of the theme from the Request.Form collection using the ID of the drop-down list control, checks that it is not an empty string or the value "-none-", and applies it to the Theme property of the Page.

Listing 12.26. Setting the Page Theme at Runtime in the Page_PreInit Event Handler

protected void Page_PreInit() {   String pagetheme = Request.Form["lstPageTheme"];   if ((pagetheme != String.Empty) && (pagetheme != "-none-"))   {     Page.Theme = pagetheme;   } }

However, there is a problem with this approach in that the order of events means that changing the theme in the page using the drop-down list and Update button only changes the stored profile value after the Page_PreInit event has completed. Therefore, ASP.NET does not apply the new theme until the next page load.

In addition, if you want the theme to apply to more than one page, as is likely to be the case when visitors select the "look and feel" they want, you must include a Page_PreInit event handler in every page. A far better approach to use instead is a central method for applying themes to all the pages within a site or a specific set of subfolders.

Using an HTTP Module to Set the Theme

ASP.NET chains requests for Web pages and the corresponding responses through a series of HTTP modules that carry out various stages of the processing of the request and response, such as authentication, setting profiles, and rendering the page. You can tap into this chain and add your own modules if you wish. You must create a class that implements the IHttpModule interface, and then add it to your web.config file so that ASP.NET executes it as part of the request process. Listing 12.27 shows the HTTP module used in this example. The class ApplyProfileToPage, declared within the ThemeModule namespace in Listing 12.27, implements the three methods of the IHttpModule interface:

  • The Init method receives a reference to the current ASP.NET application context. It adds an event handler named MyPreRequest Handler to the PreRequestHandlerExecute event of the context so that, when ASP.NET raises the PreRequestHandlerExecute event just before executing the page, it will call the MyPreRequest Handler event handler declared in this module.

  • The Dispose method is where you would dispose of any non-.NET resources you use in your module, such as database connections and file handles, before the module is destroyed. The example module here has no resources to dispose.

  • The MyPreRequestHandler routine is the event handler called when ASP.NET raises the PreRequestHandlerExecute event. In this routine, the code can access the page being executed and the current user's profile through the current HttpContext, extract the value of the PageTheme profile property, and apply it to the current page by setting its Theme property.

Listing 12.27. An HTTP Module to Set the Theme Property of All Pages

using System; using System.Web; using System.Web.UI; namespace ThemeModule {   public class ApplyProfileToPage : IHttpModule   {     public void Init(HttpApplication context)     {       context.PreRequestHandlerExecute += MyPreRequestHandler;     }     public void Dispose()     {       // do nothing     }     private void MyPreRequestHandler(Object sender, EventArgs e)     {       // get a reference to the current page       Page p = HttpContext.Current.Handler as Page;       if (p != null)       {         // get current profile as a ProfileCommon instance         ProfileCommon pc = (ProfileCommon)HttpContext.Current.Profile;         // set the Theme property of the page to the value         // in the current user's profile PageTheme property         p.Theme = pc.PageTheme;       }     }   } }

The result is that, when ASP.NET executes any page where this module is loaded into the application, the Theme property will already be set to the name of the theme stored in the current user's profile. Therefore, the only thing that remains is to arrange for ASP.NET to load this module as part of the application. This just requires an entry in the <httpModules> section of the web.config file for the application, as shown in Listing 12.28.

Listing 12.28. Adding the HTTP Module to web.config

<system.web>   ...   <httpModules>     <add name="myThemeModule" type="ThemeModule.ApplyProfileToPage" />   </httpModules>   ... </system.web>

There are two minor changes required to the Shopping Cart page to accommodate the new HTTP module. First, because the module simply applies the value of the PageTheme profile property to the page, the code in the Update ProfileValues routine that sets the value of this profile property when the user clicks the Update button must look for the value "-none-" and set the profile property value to an empty string in this case.

Second, because the HTTP module executes before the page itself, changing the profile value in the UpdateProfileValues routine will not cause the new theme to apply until the following page load. Therefore, when the user does change and save the value of the theme he or she wants to use, the UpdateProfileValues routine must cause another postback so that ASP.NET applies the newly selected theme. Listing 12.29 shows the corresponding section of the UpdateProfileValues routine with these changes implemented.

Listing 12.29. Changes to the UpdateProfileValues Routine to Set the Selected Theme

... // update the page theme if it has changed String oldTheme = Page.Theme; String newTheme = lstPageTheme.SelectedValue; if (newTheme == "-none-") {   newTheme = String.Empty; } if (newTheme != oldTheme) {   Profile.PageTheme = newTheme;   // need to reload page to pick up new theme   Response.Redirect(Request.Path, true); } ...

Because the screenshots in this book are not printed in color, it is difficult to see the detailed differences in appearance of the controls in the pages of the example. However, Figure 12.12 shows the Login control on the Login page of the site with the effects of the three themes in this example. This page is unchanged from the previous versions of the example, and yet by applying a theme across the entire site through an HTTP module, it changes to reflect the user's selected theme. This is a good indication of the power of themes for customizing your applications.

Figure 12.12. The effects of the three themes on the Login page




ASP. NET 2.0 Illustrated
ASP.NET 2.0 Illustrated
ISBN: 0321418344
EAN: 2147483647
Year: 2006
Pages: 147

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net