Introduction
There are two parts to using the ASP.NET 2.0 MasterPage system: MasterPages and ContentPages, which are two halves of a whole.
The MasterPage sets up the shape of the page, and the ContentPage's contain the actual data that is to be rendered within the spaces set up in the MasterPage (if you will, this is very similar to a Microsoft Word MailMerge operation if you will: one page is the template, another page is the data).
Creating the MasterPage
A MasterPage is a page template, within which ContentPages will be rendered.
A MasterPage is simply an ASP.NET file with the extension .master (for example, site.master).
Tip: It is often saved in a MasterPages directory in the root of the web application, but this is just a convention:
- Asp_Data
- Asp_Themes
- MasterPages
- Default.aspx
...The Page Directive:
A MasterPage differs from a regular aspx Page in that it starts off with @ Master directive rather than a @ Page directive:
<%@ Master Language="C#" %>
...
...The ContentPlaceHolder Tags:
A MasterPage can contain any static or dynamic declarative tags that a normal aspx page would contain, but its main purpose is to setup ContentPlaceHolders, which are locations/slots/spaces where other Content Pages will be putting their stuff.
<asp:ContentPlaceHolder Runat="server" ID="Body" />
Think of ContentPlaceHolders as the little spaces in a TV-dinner tray... Each TV dinner comes on the same pre-fabricated tray. The spaces are empty, just waiting for a content page (turkey roast whatever) to be put into the allocated space...
...Putting it all together:
A rudimentary MasterPage might look like the following, with a header, footer, and two columns (one for a future menu):
<%@ Master Language="C#" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<LINK REL="SHORTCUT ICON" runat="server" HREF="~/favicon.ico" type="image/x-icon">
</head>
<body>
<form id="form1" runat="server" style="">
<div style="margin:4px;border: solid 1px #C0C0FF;">
<!-- LOGO AREA -->
<h3>XAct Software Solutions, Inc.</h3>
</div>
<div>
<div style="margin:4px; border:solid 1px #C0C0C0; float:left;width:100px;background:#E0E0E0;">
<!-- MENU FRAME -->
...
</div>
<div style="margin:4px; border:solid 1px #C0C0C0;margin-left:110px;">
<!-- BODY -->
<asp:ContentPlaceHolder Runat="server" ID="Body" />
</div>
</div>
<div style="margin:4px; border:solid 1px #C0C0C0;">
<!-- FOOTER -->
<div style='position:relative;right:0px;'>
Copyright Sky Sigal, 2007.
</div>
</div>
</form>
</body>
</html>
ContentPage
Once you have a MasterPage created, its time to make a ContentPage to 'fit' into it.
...Refer back to the MasterPage:
For a ContentPage to take advantage of a MasterPage, it has to refer back to it.
This is done by updating the ContentPage's @Page directive to include a MasterPageFile attribute:
<%@ Page Language="C#" MasterPageFile="~/MasterPages/site.master" %>
...Refer back to the MasterPage's ContentPlaceHolderID:
The second thing that the ContentPage has to do is make a asp:Content tag, within which you want your page's actual content.
This asp:Content tag has to specify which ContentPlaceHolder it is intended for (where it will render) -- this is done by the ContentPlaceHolderId attribute:
<%@ Page Language="C#" MasterPageFile="~/MasterPages/site.master" Title="My Little Page..." %>
<asp:content id="Content1" runat="Server" contentplaceholderid="Body">
I'm some wonderful body...
</asp:content>
...The ContentPage is stripped of all the HTML, BODY, FORM tags:
Notice how the ContentPage is stripped of all the usual HTML, BODY, STYLE, FORM tags we are so used to in aspx pages.
This is because these were all defined in the MasterPage: we do NOT want to re-include them here -- they would just duplicated, conflict, and cause a mess.
In other words, think of a ContentPage as a half-page, complementing the MasterPage.
Note:
In a content page, anything that is not inside the Content controls (except script blocks for server code) results in an error.
The Page Title
Some of you may be wondering how the page gets titled, considering the ContentPage no longer has any html/body/head statements. This is because ASP.NET is taking over that role too. If you look back at the ContentPage, you'll notice its @Page attribute has a title attribute. If you look back at the MasterPage, you'll notice that the head tag has a runat=server setting.
Note:
Both steps are required in order for ASP.NET to set the title for the page.
What will happen is that ASP.NET will read the title from the ContentPage's Page title attribute, and inject it into the MasterPage's head tag because it has control over it (once you've attached a runat attribute to it).
Context and Referencing resources
One important point to understand is how the page resolves URLs to other elements (eg image and CSS URLs).
The context for the merged content and master pages is that of the ContentPage (ie: if you request the CurrentExecutionFilePath property of the HttpRequest object, whether in content page code or in master page code, the path represents the location of the content page).
Where you have to watch out for the effects of this is where put images and references to style sheets in the MasterPage, and make them relative, they will fail if the path is not relative also from the ContentPage.
Maybe make them resolve to the root of the application?
Nesting Master Pages
Another thing you'll need to know is that you can nest Master Pages:
Here, default.aspx will use a MasterPageFile attribute that points to folder.master, that contains a combination of asp:Content and asp:ContentPlaceHolders, and which in turn will have a MasterPageFile attribute that points back to the site.master.
This way, one can do layouts where the site.master gives the format of the site, with header, footer, and maybe a menu system, and the folder.master might just add a subheader to the layout mix:
<%@ Master Language="C#" MasterPageFile="~/MasterPages/site.master" %>
<asp:Content runat="server" ContentPlaceHolderId="SubHeader">
<div class="SiteSubHeader">
A SubHeader to the Site's Header
</div>
</asp:Content>
<asp:Content runat="server" ContentPlaceHolderId="Body">
<asp:ContentPlaceHolder runat="server" id="Body"/>
</asp:Content>
Note:
Notice how the id 'Body' can be used twice without the content page getting confused as to which Body its talking about?
Themes
It makes sense to question whether Themes can be applied directly to MasterPages.
You cannot directly apply an ASP.NET theme to a master page. If you add a theme attribute to the @ Master directive, the page will raise an error when it runs.
However, themes are applied to master pages under these circumstances:
-
If a theme is defined in the Content Page.
Master pages are resolved in the context of content pages, so the content page's theme is applied to the master page as well.
-
If the site as a whole is configured to use a theme by including a theme definition in the pages Element (ASP.NET Settings Schema) element.
That's it
That's it. Just about.
At least you know the basics of ASP.NET's MasterPage mechanism, and I hope you use it in your next project.
Further Reading
ASP.NET Master Pages Overview
Tips for Nested Master Pages and VS 2005 Design-Time