master page is similar to an ordinary ASP.NET page except for the top @Master directive and the presence of one or more ContentPlaceHolder server controls. A ContentPlaceHolder control defines a region in the master page that can be customized in a derived page. A master page without content placeholders is technically correct and will be processed correctly by the ASP.NET runtime. However, a placeholderless master fails in its primary goal—to be the supertemplate of multiple pages that look alike. A master page devoid of placeholders works like an ordinary Web page but with the extra burden required to process master pages. Here is a simple master page:
<%@ Master Language="C#" CodeFile="Simple.master.cs" Inherits="Simple" %>
<html>
<head runat="server">
<title>Hello, master pages</title>
</head>
<body>
<form id="form1" runat="server">
<asp:Panel ID="HeaderPanel" runat="server"
BackImageUrl="Images/SkyBkgnd.png" Width="100%">
<asp:Label ID="TitleBox" runat="server"
Text="Programming ASP.NET 2.0" />
</asp:Panel>
<asp:contentplaceholder id="PageBody" runat="server">
<!-- derived pages will define content for this placeholder -->
</asp:contentplaceholder>
<asp:Panel ID="FooterPanel" runat="server"
BackImageUrl="Images/SeaBkgnd.png">
<asp:Label ID="SubTitleBox" runat="server"
Text="Dino Esposito" />
</asp:Panel>
</form>
</body>
</html>
As you can see, the master page looks like a standard ASP.NET page. Aside from the identifying @Master directive, the only key differences are ContentPlaceHolder controls. A page bound to this master automatically inherits all the contents of the master (the header and footer, in this case) and can attach custom markup and server controls to each defined placeholder. The content placeholder element is fully identified by its ID property and normally doesn't require other attributes.
The @Master Directive
The @Master directive distinguishes master pages from content pages and allows the ASP.NET runtime to properly handle each. A master page file is compiled to a class that derives from the MasterPage class. The MasterPage class, in turn, inherits UserControl. So, at the end of the day, a master page is treated as a special kind of ASP.NET user control.
Description
ClassName
Specifies the name for the class that will be created to render the master page. This value can be any valid class name but should not include a namespace. By default, the class name for simple.master is ASP.simple_master.
CodeFile
Indicates the URL to the file that contains any source code associated with the master page.
Inherits
Specifies a code-behind class for the master page to inherit. This can be any class derived from MasterPage.
MasterPageFile
Specifies the name of the master page file that this master refers to. A master can refer to another master through the same mechanisms a page uses to attach to a master. If this attribute is set, you will have nested masters.
The master page is associated with a code file that looks like the following:
public partial class Simple : System.Web.UI.MasterPage {
protected void Page_Load(object sender, EventArgs e) {
...
}
}
The @Master directive doesn't override attributes set at the @Page directive level. For example, you can have the master set the language to Visual Basic .NET and one of the content pages can use C#. The language set at the master page level never influences the choice of the language at the content page level. You can use other ASP.NET directives in a master page—for example, @Import. However, the scope of these directives is limited to the master file and does not extend to child pages generated from the master.
Note
You can create master pages programmatically. You build your own class and make it inherit MasterPage. Then you create .master files in which the Inherits attribute points to the fully qualified name of your class. Rapid application development (RAD) designers such as the one embedded in Microsoft Visual Studio .NET 2005 use this approach to create master pages.
The ContentPlaceHolder Container Control
The ContentPlaceHolder control acts as a container placed in a master page. It marks places in the master where related pages can insert custom content. A content placeholder is uniquely identified by an ID. Here's an example:
<asp:contentplaceholder runat="server" ID="PageBody" />
A content page is an ASP.NET page that contains only <asp:Content> server tags. This element corresponds to an instance of the Content class that provides the actual content for a particular placeholder in the master. The link between placeholders and content is established through the ID of the placeholder. The content of a particular instance of the Content server control is written to the placeholder whose ID matches the value of the ContentPlaceHolderID property, as shown here:
<asp:Content runat="server" contentplaceholderID="PageBody">
...
</asp:Content>
In a master page, you define as many content placeholders as there are customizable regions in the page. A content page doesn't have to fill all the placeholders defined in the bound master. However, a content page can't do more than just fill placeholders defined in the master.
Note
A placeholder can't be bound to more than one content region in a single content page. If you have multiple <asp:Content> server tags in a content page, each must point to a distinct placeholder in the master.
Specifying Default Content
A content placeholder can be assigned default content that will show up if the content page fails to provide a replacement. Each ContentPlaceHolder control in the master page can contain default content. If a content page does not reference a given placeholder in the master, the default content will be used. The following code snippet shows how to define default content:
<asp:contentplaceholder runat="server" ID="PageBody">
<!-- Use the following markup if no custom
content is provided by the content page -->
...
</asp:contentplaceholder>
The default content is completely ignored if the content page populates the placeholder. The default content is never merged with the custom markup provided by the content page.
Note
A ContentPlaceHolder control can be used only in a master page. Content placeholders are not valid on regular ASP.NET pages. If such a control is found in an ordinary Web page, a parser error occurs.
Writing a Content Page
The master page defines the skeleton of the resulting page. If you need to share layout or any UI block among all the pages, placing it in a master page will greatly simplify management of the pages in the application. You create the master and then think of your pages in terms of a delta from the master. The master defines the common parts of a certain group of pages and leaves placeholders for customizable regions. Each content page, in turn, defines what the content of each region has to be for a particular ASP.NET page.
The Content Control
The key part of a content page is the Content control—a mere container for other controls. The Content control is used only in conjunction with a corresponding ContentPlaceHolder and is not a standalone control. The master file that we considered earlier defines a single placeholder named PageBody. This placeholder represents the body of the page and is placed right below an HTML table that provides the page's header.
Attaching Pages to a Master
In the previous example, the content page is bound to the master by using the MasterPageFile attribute in the @Page directive. The attribute points to a string representing the path to the master page. Page-level binding is just one possibility—although it is the most common one.
You can also set the binding between the master and the content at the application or folder level. Application-level binding means that you link all the pages of an application to the same master. You configure this behavior by setting the Master attribute in the <pages> element of the principal web.config file:
<configuration>
<system.web>
<pages master="MyApp.master" />
</system.web>
</configuration>
If the same setting is expressed in a child web.config file—a web.config file stored in a site subdirectory—all ASP.NET pages in the folder are bound to a specified master page.
Note that if you define binding at the application or folder level, all the Web pages in the application (or the folder) must have Content controls mapped to one or more placeholders in the master page. In other words, application-level binding prevents you from having (or later adding) a page to the site that is not configured as a content page. Any classic ASP.NET page in the application (or folder) that contains server controls will throw an exception.
Device-Specific Masters
Like all ASP.NET pages and controls, master pages can detect the capabilities of the underlying browser and adapt their output to the specific device in use. ASP.NET 2.0 makes choosing a device-specific master easier than ever. If you want to control how certain pages of your site appear on a particular browser, you can build them from a common master and design the master to address the specific features of the browser. In other words, you can create multiple versions of the same master, each targeting a different type of browser.
How do you associate a particular version of the master and a particular browser? In the content page, you define multiple bindings using the same MasterPageFile attribute, but you prefix it with the identifier of the device. For example, suppose you want to provide ad hoc support for Microsoft Internet Explorer and Netscape browsers and use a generic master for any other browsers that users employ to visit the site. You use the following syntax:
<%@ Page masterpagefile="Base.master"
ie:masterpagefile="ieBase.master"
netscape6to9:masterpagefile="nsBase.master" %>
The ieBase.master file will be used for Internet Explorer; the nsBase.master, on the other hand, will be used if the browser belongs to the Netscape family, versions 6.x to 9.0. In any other case, a device-independent master (Base.master) will be used.