Chapter 3: Pages and Design (Part 2 of 2)

This article is an excerpt from Inside Microsoft Windows SharePoint Services 3.0 by Ted Pattison and Daniel Larson, from Microsoft Press (ISBN 9780735623200, copyright 2007 by Microsoft Press, all rights reserved). No part of these chapters may be reproduced, stored in a retrieval system, or transmitted in any form or by any means—electronic, electrostatic, mechanical, photocopying, recording, or otherwise—without the prior written permission of the publisher, except in the case of brief quotations embodied in critical articles or reviews.

Previous Part: Chapter 3: Pages and Design (Part 1 of 2)

Download the sample code that accompanies the book

Contents

  • Master Pages

  • Branding SharePoint Sites by Using CSS Files

  • Summary

One of the most tedious aspects of customizing and branding sites in Windows SharePoint Services 2.0 has to do with creating a consistent look and feel across pages. The root of this problem is caused by the fact that Microsoft ASP.NET 1.1 does not provide an effective page-templating technique that can be used to define a common layout across the pages within a Windows SharePoint Services 2.0 site. As a result, many developers and designers working with Windows SharePoint Services 2.0 and Microsoft Office SharePoint Portal Server 2003 have resorted to copying and pasting HTML layouts from page to page. As you can imagine, this makes it very hard to customize and maintain sites whose layout requirements differ from the out-of-the-box experience you get with a standard Windows SharePoint Services 2.0 site.

When master pages were introduced with Microsoft ASP.NET 2.0, they were embraced by developers because they provide a more elegant way to define the common layout for all pages within a site. The fact that Windows SharePoint Services 3.0 was designed from the ground up around the concept of master pages is a very welcome change for those with experience branding sites with the previous version of Windows SharePoint Services.

The last chapter reviewed the basic ASP.NET architecture for master pages. A master page is a template that allows you to define a standard page layout for an entire site with common elements, such as a banner and navigation controls. The pages that link to a master page are known as content pages. The key concept is that each content page that links to a master page benefits from the shared layout and then can extend that master page by using replaceable named placeholders to add unique content.

In this book, you have already seen several places where master pages have been used. In the previous chapter, you saw that the majority of standard SharePoint application pages link to a master page in the virtual _layouts directory named application.master. You have also seen that you can link to application.master when creating your own custom application pages.

In this chapter, you have seen how to create page templates for site pages that link to the standard master page named default.master. This makes it very simple to create site pages that have the same look and feel as the standard site pages that are provided with Windows SharePoint Services 3.0.

As you begin to think through the bigger picture with respect to branding SharePoint sites with master pages, there is one critical factor to keep in mind. Site pages and application pages use separate master pages. In this chapter, we will examine how to provision and use a custom master page for the site pages within a site. This technique allows you to change the layout for every site page within any site to which you want to apply your own custom branding. However, the technique being covered in the next section cannot be applied to application pages because the majority of standard SharePoint application pages rely on a single master page named application.master that cannot be replaced or customized on a site-by-site basis.

Understanding default.master

Every Windows SharePoint Services 3.0 site is provisioned with a special catalog known as the Master Page gallery containing a master page template named default.master. This standard master page is deployed during the standard Windows SharePoint Services installation on the file system of the front-end Web server at the following path (there is a line break in the file path to make it more readable).

C:\Program Files\Common Files\Microsoft Shared

\web server extensions\12\TEMPLATE\GLOBAL\default.master

Whenever you create a new site, Windows SharePoint Services provides provisioning instructions to create the Master Page gallery and provision an instance of default.master within the site by using a standard site-relative path.

/_catalogs/masterpage/default.master

The default.master page is widely used in Windows SharePoint Services. It defines a common layout for every site's home page (default.aspx) as well as all of the standard Windows SharePoint Services form pages associated with lists and document libraries (e.g., AllItems.aspx or NewItem.aspx). The default.master page can also serve as the master page for your custom site pages, as has been demonstrated in all of the page templates used in the CustomSitePages project.

To understand the best practice for creating site pages that link to default.master, it's important that you have a basic understanding of what's defined inside this file. It's definitely worth your time to open up a copy of the default.master file within Microsoft Visual Studio and try to absorb all that's there. While it might take some time to get to know everything inside, it's a worthwhile investment for any developer serious about mastering development in Windows SharePoint Services.

The default.master page contains the basic layout for a site page including elements such as HTML, HEAD, BODY, and FORM. Within these standard HTML elements, you will find three important types of components:

  • Controls for links, menus, icons, and navigation components

  • Named placeholders

  • Delegate controls

Many server-side controls that are used to construct the default.master page template represent encapsulated logic and user interface components that are compiled into the Microsoft.SharePoint assembly. Examples of these controls include the SPWebPartManager object and controls to provide navigation components, such as breadcrumb trails and menus for navigating around the site.

Named placeholders provide an extensibility mechanism used to add unique content to a page template or page instance that is linked to a master page. Delegate controls provide an elegant way to substitute elements into the layout of default.master that affects every site page that links to it. The following fragment is extracted from default.master and is simplified to demonstrate how each of these component types is used.

<%@Master language="C#"%> 

<%@ Register Tagprefix="SharePoint"  
    Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, …" %>  

<HTML > 

<HEAD > 

    <!-- SharePoint Utility Controls --> 
    <SharePoint:CssLink ID="CssLink1" /> 
    <SharePoint:Theme ID="Theme1" /> 

    <!-- Named Placeholders --> 
    <Title ID=onetidTitle> 
      <asp:ContentPlaceHolder id=PlaceHolderPageTitle /> 
    </Title> 
    <asp:ContentPlaceHolder id="PlaceHolderAdditionalPageHead"  
                            /> 

    <!-- Named Delegate Control --> 
    <SharePoint:DelegateControl ID="DelegateControl1"   
                               ControlId="AdditionalPageHead"  
                               AllowMultipleControls="true"/> 
</HEAD>

The HEAD element of default.master shows the use of standard Windows SharePoint Services server-side controls, such as CssLink and Theme. These controls contain the encapsulated logic to integrate the standard cascading style sheet (CSS) files used by Windows SharePoint Services and supply the support required for user-applied themes. Note that these same two controls are also present inside application.master so that the standard CSS files and themes continue to work as users navigate to application pages.

You can also see that the HEAD element defines two named placeholders with an ID of PlaceHolderPageTitle and PlaceHolderAdditionalPageHead. The placeholder named PlaceHolderPageTitle makes it possible to substitute the page title when creating a page template or customizing a site page instance. The placeholder named PlaceHolderAdditionalPageHead makes it possible to add items such as extra meta tags into the HEAD section. The following example displays a page template that substitutes these two placeholders with unique content.

<%@ Page MasterPageFile="~masterurl/default.master" %> 

<asp:Content ID="PageTitle"   
             ContentPlaceHolderID="PlaceHolderPageTitle"> 
  My Custom Page Title 
</asp:Content> 

<asp:Content ID="AdditionalPageHead"   
             ContentPlaceHolderID="PlaceHolderAdditionalPageHead"> 
  <META name="keywords" content="Software, Consulting, Money, Fame" /> 
</asp:Content>

Windows SharePoint Services Navigation Components

Several standard controls are included with default.master that provide the basic infrastructure for navigation. For example, the control that has been positioned at the very top of the page populates a breadcrumb navigation menu that allows users to navigate from the current site upward to the parent site and all the way to the top-level site of the current site collection.

Navigation in Windows SharePoint Services is based on the navigation-provider infrastructure introduced in ASP.NET 2.0. In this model, a navigation provider is designed and created to provide a set of navigation nodes. In many cases, the nodes supplied by a navigation provider can be bound to a menu control or a tree view to give users a user interface component with which to navigate around the site.

Windows SharePoint Services provides several standard navigation providers such as the SPNavigationProvider, SPSiteMapProvider, SPContentMapProvider, and SPXmlContentMapProvider classes. You can see where all the active navigation providers are defined by examining the siteMap section inside the system.web section of the standard Windows SharePoint Services web.config file.

The top link bar and the Quick Launch menu represent the two main navigation components defined in default.master. The top link bar is defined by using a Windows SharePoint Services–specific control of type AspMenu along with a SiteMapDataSource control that is configured to point to the standard SPNavigationProvider component. The Quick Launch menu is defined in the same way. The major difference between the two is that the SiteMapDataSource for the top link bar is configured with a StartingNodeUrl attribute with a value of sid:1002, whereas the Quick Launch menu is configured with a StartingNodeUrl attribute with a value of sid:1025.

The next question you should be asking is what the significance is between 1002 and 1025. It has to do with the data stored in the content database for tracking navigation nodes. The top node for the top link bar has an ID of 1002, and the top node to the Quick Launch menu has an ID of 1025.

Windows SharePoint Services provides users with the flexibility to add navigation nodes to either the top link bar or the Quick Launch menu. You can access the application pages that allow users to perform these actions from the Site Settings page. What’s nice about this scheme for developers is that you can customize the standard Windows SharePoint Services navigation menus without making any changes to default.master. You simply need to find a way to add new navigation nodes to the content database.

While it's possible for users to add navigation nodes through site administration pages in the browser-based user interface, it's also possible and far more flexible to accomplish the same goal by using the Windows SharePoint Services object model. The CustomSitePages feature provides code in the FeatureActivated event handler to add navigation nodes to construct a custom drop-down menu in a fashion that is not possible to replicate through the user interface. Examine the following code and observe how it creates SPNavigationNode objects and adds them to the collection of nodes that define the structure for the top link bar.

public override void FeatureActivated(SPFeatureReceiverProperties properties) { 

  // get a hold of current site in context of feature activation 
  SPWeb site = (SPWeb)properties.Feature.Parent; 
  SPNavigationNodeCollection topNav = site.Navigation.TopNavigationBar;       

  // create dropdown menu for custom site pages 
  SPNavigationNode DropDownMenu1; 
  DropDownMenu1 = new SPNavigationNode("Site Pages", "", false); 
  topNav[0].Children.AddAsLast(DropDownMenu1); 

  // add navigation nodes to create menu items 
  DropDownMenu1.Children.AddAsLast( 
      new SPNavigationNode( "Site Page 1",    
                            "SitePages/Page01.aspx")); 
  DropDownMenu1.Children.AddAsLast( 
      new SPNavigationNode("Site Page 2",  
                            "SitePages/Page02.aspx")); 
}

Delegate Controls

Windows SharePoint Services introduces a powerful new extensibility mechanism known as delegate controls. In some ways, a delegate control is similar to a named placeholder because it defines a region inside a master page that can be substituted with unique content to meet the needs of a particular business solution. Like a placeholder, a delegate control can optionally supply default content that is used until a substitution is performed.

One major difference when compared to placeholders is that the substitution mechanism for replacing the contents of a delegate control is driven through feature activation. Therefore, you can replace what’s defined inside a delegate control in default.master without requiring any changes to default.master or the site pages that link to it. All you need to do is define a Control element within a feature and then activate that feature.

A significant aspect of using delegate controls involves the scope of the feature that is being used to drive substitution. When you design a feature to substitute the contents of a delegate control, your feature can be scoped at any of the four supported levels. These levels include site scope, site collection scope, Web application scope, and farm scope. This dimension of delegate controls provides a powerful mechanism for enabling and disabling functionality on a wide-scale basis.

Let's begin by looking at an example of a delegate control that is defined in default.master to create the region that defines the standard search area in site pages just above the Site Settings menu. The delegate control definition in default.master looks like the following.

<SharePoint:DelegateControl  
  ID="DelegateControl5"  
    
  ControlId="SmallSearchInputBox"  
/>

This is an example of a delegate control that defines no default content. Instead, the default content for this delegate control is supplied by a standard Windows SharePoint Services feature named ContentLightup. The ContentLightup feature defines a Control element that substitutes content into the SmallSearchInputBox delegate control by referencing a built-in user control with the standard Windows SharePoint Services search area content.

<Control  
  Id="SmallSearchInputBox"  
  Sequence="100"  
  ControlSrc="~/_controltemplates/searcharea.ascx"  
/>

Assume that you want to get rid of the standard search area content and replace it with your own custom content for a particular business solution. That's what delegate controls were designed for. If you want to follow along with the sample code that accompanies this chapter, you should open the Visual Studio project named CustomBranding. This project contains the definition for a feature named CustomBranding that is scoped to the level of a site collection.

If you want to replace a delegate control, such as the Windows SharePoint Services search area, with your own customized version, you start by adding a Control element to a feature. The Control element should have an ID value of SmallSearchInputBox. The Control element should also have a sequence number smaller than any other active Control element pointing to the same ID. The following code demonstrates how the Control element is defined inside the elements.xml file of the CustomBranding feature.

<Control  
  Id="SmallSearchInputBox"  
  Sequence="10"  
  ControlSrc="~/_controltemplates/Litware/LitwareSearchArea.ascx"  
/>

Note that this Control element has a sequence number of 10, which is smaller than the Control element defined in ContentLightup with a sequence number of 100. Once the CustomBranding feature is activated within a site collection, all of the site pages that link to default.master replace the standard Windows SharePoint Services search area with whatever content you have defined inside the custom user control named LitwareSearchArea.ascx. The following code defines a starting point for creating a custom user control that supplies custom search behavior.

<%@ Control Language="C#" %> 

<script > 
    protected void cmdRunSearch_Click(object sender, EventArgs e)    { 
      // LEFT AS AN EXERCISE FOR THE READER 
      // Step 1: add code here to perform custom search 
      // Step 2: redirect user to custom search results page 
    } 
</script> 

<table> 
  <tr> 
    <td> 
      <asp:Button ID="cmdRunSearch"  Text="Search" 
                  OnClick="cmdRunSearch_Click" /> 
    </td> 
    <td> 
      <asp:TextBox ID="txtSearchText"  Width="120" /> 
    </td> 
  </tr> 
</table>

While the CustomBranding feature is designed to activate at the level of a site collection, remember that delegate controls can be substituted at any scope supported by features. You can add the Control element that substitutes the delegate control named SmallSearchInputBox to a feature scoped at the Web application or farm level to replace the standard Windows SharePoint Services search area on a larger scale.

If you have plans to replace the Windows SharePoint Services search area by using a Control element, it's important for you to understand that Microsoft Office SharePoint Server 2007 (MOSS) uses the same approach. The Standard Edition of MOSS provides a feature that replaces the SmallSearchInputBox delegate control by using a Control element with a sequence number of 50. The Enterprise Edition of MOSS provides a feature that replaces the SmallSearchInputBox delegate control by using a Control element with a sequence number of 25.

The main point here is that you obtain a more enhanced version of the search area as you upgrade from Windows SharePoint Services to MOSS Standard Edition and then to MOSS Enterprise Edition. You should assign the sequence number for your Control element accordingly, depending on whether you want to override the enhanced versions of the search area supplied by MOSS.

In addition to substituting delegate controls by using .ascx files, Windows SharePoint Services also supports delegate control substitution by using control classes that are compiled into assemblies installed in the global assembly cache. As an example, let's examine a technique for replacing the SiteMapDataSource that is used to populate the Quick Launch menu. Examine the following fragment from the standard default.master page template that defines a delegate control named QuickLaunchDataSource.

<SharePoint:DelegateControl  
     ID="DelegateControl8"   
     ControlId="QuickLaunchDataSource"> 
  <Template_Controls> 
    <asp:SiteMapDataSource  
      SiteMapProvider="SPNavigationProvider" 
      ShowStartingNode="False"  
      id="QuickLaunchSiteMap"  
      StartingNodeUrl=":1025" 
       /> 
  </Template_Controls> 
</SharePoint:DelegateControl>

Unlike the last example of a delegate control, this delegate control with a ControlId of QuickLaunchDataSource defines default content that is used until a substitution is performed. The default content includes a SiteMapDataSource control with an ID of QuickLaunchSiteMap. If you want to substitute this control with a different SiteMapDataSource control, you can add the following Control element to a custom feature.

<Control  
 Id="QuickLaunchDataSource" Sequence="1"      
 ControlAssembly="System.Web, ..." 
 ControlClass="System.Web.UI.WebControls.SiteMapDataSource"> 
  <Property Name="ID">QuickLaunchSiteMap</Property> 
  <Property Name="SiteMapProvider">SPSiteMapProvider</Property> 
  <Property Name="ShowStartingNode">False</Property> 
</Control>  

As shown in the previous example, this Control element provides an ID that matches the ControlId of the target delegate on which the substitution should be performed. However, this example differs because it uses the ControlAssembly and ControlClass attributes to reference a specific control type within a target assembly.

You should also observe that the Control element contains several nested Property elements that define the initialization parameters for the control instance being used in the substitution. It is important in this example that the control instance being created is assigned an ID of QuickLaunchSiteMap because the hosting page expects to find a control of that name. The control instance is also initialized to use the SPSiteMapProvider class, which provides different behavior than the default that uses the SPNavigationProvider class instead.

Customizing default.master

The previous section of this chapter demonstrated several branding techniques involving placeholder and delegate controls that did not require making any changes to default.master. However, many developers and end users alike will come to the conclusion that they want to make changes to default.master. This is something that Microsoft Office SharePoint Designer makes very easy to accomplish. You can simply open default.master and make whatever changes you want. Office SharePoint Designer makes it possible to work in either Code view or Design view when you are customizing a master page such as default.master.

From an architectural standpoint, it's important to acknowledge that the default.master page follows the same rules for ghosting and unghosting as the site pages that link to it. When a site is initially created, default.master is uncustomized. When site pages that link to default.master are requested, the master page template is loaded from the file system of the front-end Web server and processed like any other ghosted page. However, default.master becomes unghosted once a user customizes it with SharePoint Designer. These customization changes are stored inside the content database just like customizations to site pages, such as default.aspx. From that point on, default.master is processed like any other customized page and must follow all of the rules of safe mode processing.

Note that it's possible to customize the master page for a site while leaving the site pages that link to it uncustomized. Likewise, it's possible to customize one or more site pages while leaving their underlying master page uncustomized. Furthermore, if you customize either the master page or site pages and later wish to undo your changes, both the browser-based UI of Windows SharePoint Services and SharePoint Designer provide simple menu commands to discard customization changes from the content database and revert back to the original page template.

Even though customizing a master page with SharePoint Designer provides a quick and easy way to make changes, it's difficult to track these changes in a source code management system. It’s also difficult to make such customization changes repeatable across site collections in a large-scale deployment. Instead of using this type of customization strategy, a better approach for a developer is to create a page template for a custom master page. This topic is covered in the next section of this chapter.

Creating a Custom Master Page Template

Creating a custom master page template involves several steps. First, you must create the master page template itself. Second, you must create a custom feature that provisions an instance of this master page template inside the gallery for a specific site. Finally, you need to add some code to redirect site pages to use your custom master page instead of using default.master. The Visual Studio project named CustomBranding provides a working sample that demonstrates how all of the pieces fit together.

Remember that the CustomBranding feature is scoped to the level of the site collection. While you can create a custom feature scoped at the site level to integrate a custom master page template, it’s better to design such a feature at the site collection level because users typically want branding to occur at this level. It is less convenient if you force users to activate the feature separately for every site within a site collection.

You can create a custom template by using two different approaches. First, you can make a copy of default.master and then modify it according to taste. A second approach involves starting from scratch so that you can design the exact HTML layout you’re looking for. If you start from scratch, be sure to think through which named placeholders you need to include. There are over 30 named placeholders defined inside default.master, and many of the standard site pages, such as default.aspx and AllItems.aspx, assume that whatever master page they link to will have these same named placeholders.

If you forget to include the same set of named placeholders found in default.master, you will likely experience problems. ASP.NET generates errors whenever it finds that a site page references a named placeholder that is not defined in the master page to which it is linked.

The custom master page template used in the CustomBranding project is named Litware.master. The Litware.master template is a variation on the default.master template with changes to allow for fly-out menus on both the top link bar and Quick Launch menu. The CustomBranding feature includes a Module element that has been designed to provision an instance of the Litware.master page template into the gallery of the top-level site.

<Module Name="MasterPages" List="116" Url="_catalogs/masterpage"> 
  <File Url="Litware.master" Type="GhostableInLibrary" /> 
</Module>

Note that this Module element has several differences compared with the Module element for provisioning site pages shown earlier in this chapter. While the previous Module was used to provision pages into a site, it did not target a document library. However, this Module targets the gallery, which is a special type of document library. Therefore, the Module is defined with a List attribute of 116, which is the list type identifier for the gallery. The Url attribute for this Module is defined with a value of _catalogs/masterpage, which is the standard site-relative path to the gallery.

If you examine the File element that provisions an instance of Litware.master, you notice that the Type attribute has a value of GhostableInLibrary as opposed to a value of Ghostable that was shown earlier when provisioning site pages inside a site but outside the scope of a document library. A value of GhostableInLibrary should be used whenever you are provisioning an instance of a file, such as a master page template, inside a target document library.

We have reviewed the steps involved in creating a master page template and provisioning an instance of it in the gallery of the top-level site. The next step involves redirecting all site pages within a site to link to this provisioned instance of our custom master page template. To understand the technique for accomplishing this, take a closer look at the MasterPageFile attribute defined within a Page directive. Examine the following page template, which is defined to link to a target master page by using a special syntax in the form of ~masterurl/default.master.

<%@ Page MasterPageFile="~masterurl/default.master" %> 

<asp:Content ContentPlaceHolderId="PlaceHolderMain" > 
  Custom content goes here 
</asp:Content>

The value of ~masterurl/default.master represents a tokenized reference to a master page that can be changed programmatically on a site-wide basis. The support for tokenized master page references is provided by the SPVirtualPathProvider class. The way things work is that the SPVirtualPathProvider class reads the value of an SPWeb property named MasterUrl at run time and then parses this value into the MasterPageFile attribute of an .aspx file before sending it to the ASP.NET page parser. You can redirect any site page that uses this token by acquiring an SPWeb reference to the current site and then updating the MasterUrl property.

SPWeb site = SPContext.Current.Web; 
string MasterUrlPath = site.ServerRelativeUrl; 
if (!MasterUrlPath.EndsWith(@"/")) 
  MasterUrlPath += @"/"; 
MasterUrlPath += @"_catalogs/masterpage/Litware.master"; 
site.MasterUrl = MasterUrlPath; 
site.Update();

From this code, you can see that a MasterUrl property value should be parsed together using the ServerRelativeUrl property. You should also note that the ServerRelativeUrl property ends with a forward slash in some sites, but not all sites. Therefore, you should add conditional logic to append the forward slash onto the end of the ServerRelativeUrl property if it is not already there. Next, you should append a site-relative path to the master page instance where it exists inside the gallery. Once you parse together the complete server-relative path to the master page instance, you can assign that value to the MasterUrl property of the current SPWeb object and call the Update method to save your changes.

It's important to remember that the gallery is scoped at the site level and not the site collection level. Do not be confused into thinking that all sites inside a site collection automatically use the same master page instance. Each site has its own gallery with its own default.master instance as well as its own MasterUrl property. You must supply additional code if you want all child sites within a site collection to synchronize on a single master page instance in the Master Page gallery of the top-level site. With the use of recursion, it's not too difficult to write the code against the Windows SharePoint Services object model to accomplish this task.

The CustomBranding project provides a custom application page named CustomBrand.aspx that provides code to redirect all site pages within a site collection to link to the instance of litware.master that is provisioned in the gallery of the top-level site. Once you activate the CustomBranding feature, you can navigate to the application page named CustomBrand.aspx by using a custom menu item that is added to the Site Settings menu. This application page provides a command button that allows the user to execute the following code.

protected void cmdApplyCustomBrand_Click(object sender, EventArgs e) {     
  SPWeb site = SPContext.Current.Site.RootWeb 
  string MasterUrlPath = site.ServerRelativeUrl; 
  if (!MasterUrlPath.EndsWith(@"/")) 
    MasterUrlPath += @"/"; 
  MasterUrlPath += @"_catalogs/masterpage/Litware.master"; 
  ApplyCustomBrand(MasterUrlPath, site);     
} 

protected void ApplyCustomBrand(string MasterUrlPath, SPWeb site) { 
  site.MasterUrl = MasterUrlPath; 
  site.Update(); 
  // use recusion to update all child sites in site collection 
  foreach (SPWeb child in site.Webs) { 
    ApplyCustomBrand(MasterUrlPath, child); 
  } 
}

The code in the event handler named cmdApplyCustomBrand_Click begins by parsing together the server-relative path to the instance of Litware.master in the gallery of the top-level site. The event handler then calls a method named ApplyCustomBrand to update the MasterUrl of the top-level site.

However, the ApplyCustomBrand method has also been written to enumerate through all child sites below the top-level site and recursively call itself to update them. This recursion continues to crawl the hierarchy of child sites until the MasterUrl property of every site within the site collection is updated to redirect all site pages so that they link to the instance of litware.master that is provisioned in the gallery of the top-level site.

This technique provides a quick and easy approach to redirect all site pages within a site collection to a custom master page. It works well because all standard Windows SharePoint Services site pages, such as default.aspx and AllItems.aspx, are all defined by using the dynamic token ~masterurl/default.master. You can follow suit by defining site page templates using the same technique demonstrated in this chapter.

In addition to ~masterurl/default.master, there is another dynamic token for master pages in the form of ~masterurl/custom.master. This dynamic token works in conjunction with the CustomMasterUrl property of a site and provides a secondary target master page that can be switched out programmatically. This allows you to create designs in which you can switch the master page used by your custom page templates while leaving the standard Windows SharePoint Services pages alone so they continue to link to default.master.

In addition to the two dynamic tokens presented in this chapter, Windows SharePoint Services also supports two static master page tokens that start with either ~site or ~sitecollection. These static tokens allow you to hardcode a relative path to a master page from the root of either the current site or the current site collection. This allows you to create site page templates that point to a specific custom master page instance without requiring any code to perform redirection.

Branding SharePoint Sites by Using CSS Files

In the final section of this chapter, we will discuss a few additional topics that are relevant to branding sites. First, we will examine how Windows SharePoint Services uses cascading style sheets (CSS) and discuss how to extend this support in a custom branding solution. We will then examine how to replace the image used in the standard Windows SharePoint Services page banner by using a custom graphics file.

Understanding Core.css

The look and feel of every SharePoint site is controlled through a standard set of CSS files. The Windows SharePoint Services team created a separate set of CSS files for each spoken language supported by Windows SharePoint Services. You can find the standard CSS files that are localized for US English at the following path within the Windows SharePoint Services TEMPLATE directory.

\TEMPLATE\LAYOUTS\1033\STYLES\

The file that defines the majority of the standard CSS classes used by pages in Windows SharePoint Services is named core.css. Windows SharePoint Services was designed so that every site page and every application page is automatically linked to core.css. The support for setting up these links is included in a Windows SharePoint Services–specific control named CssLink shown earlier in this chapter. The CssLink control contains logic to link the current page to the most appropriate localized version of core.css. This decision is made by examining the regional settings for the current site and also determining what language packs are installed within the farm.

If you have never looked inside core.css, you should make a copy of this file and examine what's inside. This exercise is somewhat intimidating at first because core.css contains over 4,000 lines of CSS class definitions. However, understanding which CSS classes are defined by the Windows SharePoint Services team and learning where they are used becomes an essential aspect of branding SharePoint sites.

It's important to understand that the core.css file is scoped at the farm level. Changes made to core.css affect every site in the farm; therefore, this is not a file that you should customize. Furthermore, the team at Microsoft responsible for creating updates to Windows SharePoint Services reserves the right to install an updated version of core.css in future service packs, and such an action would overwrite any changes you make to core.css today.

Windows SharePoint Services provides two recommended techniques for extending the CSS classes defined inside core.css. The first approach involves the use of Windows SharePoint Services themes and is targeted at end users. The second approach is targeted at developers and involves creating a secondary CSS file to extend and override the CSS classes defined inside core.css.

Windows SharePoint Services Themes

Windows SharePoint Services allows users to quickly change the look and feel of a SharePoint site by changing its theme. The Windows SharePoint Services support for changing themes is supplied by a standard application named themeweb.aspx that is accessible through a link on the Site Settings page.

Each theme is defined within its own directory on the front-end Web server. Themes are located in a THEMES directory within the TEMPLATE directory. For example, the built-in theme named Citrus is defined by a set of files residing in the following directory.

TEMPLATE\THEMES\CITRUS

If you examine the directory for a theme, you find that it includes CSS files and graphics files. When a user chooses a theme, Windows SharePoint Services copies all of these files up into the site, including a primary CSS file. Windows SharePoint Services also adds a link to the primary CSS file to each application page and each site page. Note that this link is always added after the link to core.css so that CSS classes inside the theme’s CSS file override CSS classes defined inside core.css.

Once a user applies a theme to a site, the CSS files can be further customized by using SharePoint Designer. For example, you can open a site that already has a theme applied in SharePoint Designer and open the primary CSS file. Any changes you make to this CSS file are stored as ordinary customization with the content database.

From a design perspective, you should observe that themes are targeted more toward end users than developers. While you can create custom themes and deploy them in a Windows SharePoint Services environment, the main idea is that themes are added to Windows SharePoint Services to support the ability of users to enable or disable them on demand. If you want a site to have specific branding without giving the user control over enabling or disabling it, you should use a custom CSS file as shown in the next section.

AlternateCSS Property

It's fairly easy to integrate a custom CSS file into a custom branding solution. The Visual Studio project named CustomBranding that accompanies this chapter provides an example of how to accomplish this by copying a custom CSS file named LitwareBrand.css and some accompanying graphics files to the following directory.

TEMPLATE\LAYOUTS\1033\STYLES\Litware

You simply need to update an SPWeb property named AlternateCssUrl in each site where you want to apply your custom theme. Note that when you apply a custom CSS file, it's also a good idea to disable any theme applied by a user so that the CSS classes from a theme do not conflict with the ones defined in your custom CSS file. As shown in the following example, you can see that this step doesn't take much code to accomplish.

SPWeb site = SPContext.Current.Web; 
site.ApplyTheme(""); 
site.AlternateCssUrl = "/_layouts/1033/STYLES/Litware/LitwareBrand.css"; 
site.Update();

Site Icon

In addition to supporting custom CSS files, Windows SharePoint Services also provides a property so that you can substitute the standard Windows SharePoint Services banner image with one more appropriate for your brand. The CustomBranding project contains a graphics file named LitwareFullLogo.png. This file is deployed inside the TEMPLATE\IMAGES directory in the following location.

TEMPLATE\LAYOUTS\Litware\LitwareFullLogo.png

It takes a few lines of code to replace the standard Windows SharePoint Services site logo with your own.

SPWeb site = SPContext.Current.Web; 
site.SiteLogoUrl = "/_layouts/images/Litware/LitwareFullLogo.png"; 
site.Update();

Best Practices for Site Branding

You have encountered several different techniques for adding custom branding to a site. The CustomBranding project provides a feature scoped to the site collection level that allows you to apply all of these branding techniques to all sites within a site collection. We will now examine all code behind the command button in the application page named CustomBrand.aspx. This example extends what was shown earlier by adding extra code so as to add a custom style sheet and custom site log, in addition to redirecting all of the site pages so that they link to Litware.master.

protected void cmdApplyCustomBrand_Click(object sender, EventArgs e) { 
  SPWeb site = SPContext.Current.Web; 
  string MasterUrlPath = site.ServerRelativeUrl; 
  if (!MasterUrlPath.EndsWith(@"/")) 
    MasterUrlPath += @"/"; 
  MasterUrlPath += @"_catalogs/masterpage/Litware.master"; 
  ApplyCustomBrand(MasterUrlPath, site);   
  Response.Redirect(Request.RawUrl); 
} 

protected void ApplyCustomBrand(string MasterUrlPath, SPWeb site) { 
  site.MasterUrl = MasterUrlPath; 
  site.ApplyTheme(""); 
  site.AlternateCssUrl = 
    "/_layouts/1033/STYLES/Litware/LitwareBrand.css"; 
  site.SiteLogoUrl = "/_layouts/images/Litware/LitwareFullLogo.png"; 
  site.Update(); 
  // use recursion to update all sites in site collection 
  foreach (SPWeb child in site.Webs) { 
    ApplyCustomBrand(MasterUrlPath, child); 
  } 
}

The CustomBranding project provides the code to enable and disable custom branding for a site collection through an application page with command buttons. However, you can extend this example and add the same code to the FeatureActivated event handler so that branding is applied whenever the CustomBranding feature is activated. You can even take this example one step further by writing code to enumerate every through site collection in a farm and activate the CustomBranding feature in each of these site collections along the way.

One final observation that we want you to make is that some branding techniques work across both site pages and application pages, which is the case for both the custom CSS file applied by using the AlternateCssUrl property as well as the site logo that can be replaced by using SiteLogoUrl. This occurs because support for these items is included in both the standard application.master template and the default.master template. However, the technique shown in this chapter for branding sites with a custom master page doesn’t extend to application pages. Therefore, you might decide to do as much branding as possible by using CSS files and the replaceable site logo.

Summary

This chapter began with a detailed look into the architecture of site pages. You should now have a solid understanding of how Windows SharePoint Services supports page customization as well as the how and why behind safe mode processing. The chapter also provided an introduction to considering how to create business solutions that leverage page templates constructed using controls and Web Part zones.

The second part of this chapter discussed master pages and offered recommendations on the best practices for creating a custom branding solution. You learned that many different techniques can be used including the creation of a custom master page template and custom CSS file as well as using a custom site logo. For Windows SharePoint Services developers who worked with previous versions of Windows SharePoint Services, it should be clear that the support offered by Windows SharePoint Services 3.0 is significantly enhanced over the support offered in previous versions.