ASP.NET 2.0 #2: Master Pages

A realistic starting point for the coding on many Web projects is static mock-ups provided by a graphics designer. What happens next? One thing that might happen is that the project leader divides up the static mock-ups among the developers, along with copies of the written specifications, and tells everyone to build pages that look like the mock-ups and that work in accordance with the specifications. A somewhat superior process would be for one or two of the senior software designers to identify custom controls, classes, and approaches that would be reusable across several of the pages, and to implement those for the rest of the developers to use as exemplars. Yet, even if the senior folk were to do that, when the developers actually get down to work, they still have to start by taking the HTML tags in the static mock-up pages and copying those into their ASP.NET pages. With ASP.NET 2.0, a more efficient process is possible, by which the senior software designers can create templates of ASP.NET pages for the developers working on the pages to use as their starting point. Those templates are called, Master Pages. 

Here is a sample page which a moderately rich layout: 

 

 

Building a Master Page is very straightforward. Using the HTML from one’s static mock-ups as a starting point, one lays out the page as one normally would any ASP.NET page. However, for those parts of the page that would vary among the individual pages that are based on the master, one inserts an instance of the new ASP.NET ContentPlaceholder controls. 

 

Creating a Web page based on the Master Page is easy to do. One adds a new Web Form to one’s project in the usual way, opting to Choose master page from the Add New Item dialog box. Visual Studio prompts you to select the master page to use as the template from among those included in the project, and then it generates a file that contains only an @Page directive that has the MasterPageFile attribute set refer to the master page one had selected as the template. Yet, in spite of its paucity of content, if one examines the page in Visual Studio’s Web form designer’s Design view, then it is apparent that the content is actually already as elaborate as the master page itself. 

 

Wherever the designer of the master page had allowed for custom content to be included in the page, white squares show up in the designer. Right-clicking on those squares permits one to go ahead and start adding the content that is specific to the page within the areas delineated for that purpose by the master page designer. Behind the scenes, Visual Studio inserts ASP.NET Content controls into the mark-up that defines the layout for the page. If one prefers to work directly with that mark-up rather than via the Web Form designer, then one has the option of composing the tags for ASP.NET Content controls manually, and connecting those controls to the ContentPlaceholder controls in the master page by assigning the value of the ID attribute of the ContentPlaceholder control in the master page to the ContentPlaceholderID attribute of the ASP.NET Content control. 

 

What you should find in working with Web forms based on master pages is that the forms seldom have any content besides controls, that most of the HTML for the layout of the forms gets abstracted out into the master pages. So, the Master Pages facility within ASP.NET 2.0 provides at long last with a development environment for Web applications in which the appearance of the Web pages is fully abstracted out of the application. With the code-behind feature introduced in ASP.NET 1.0, or with Visual Basic 6 Web Forms to be more precise, the behaviour of the application could easily be separated from the appearance of the pages, but the controls of the application were still wound up together with the HTML controlling the appearance, within the .aspx files. With the proper use of Master Pages, the HTML evaporates out of the individual pages and into the masters, which is a big step forward. 

Here is a page with a moderately rich layout:

Here is the entire contents of the ASPX file: note the absence of layout markup:

 <%@ Page Language="C#" MasterPageFile="~/Masters/Contracts/DocumentManagement/Reception.master" CompileWith="Reception.aspx.cs" ClassName="Reception_aspx" Title="Contract Document Receiving Page" %>
<%@ Register tagprefix="ctl" TagName="Header" Src="../../CustomControls/Header.ascx"%>
<%@ Register tagprefix="ctl" TagName="NumericTextBox" Src="../../CustomControls/NumericTextBox.ascx" %>

<asp:Content ID="Header" ContentPlaceHolderID="HeaderControlPlaceHolder" Runat="Server">
<script language="jscript" src="/scripts/Saler/Contracts/DocumentManagement/Reception.js"></script>
<ctl:Header
id="HeaderControl"
runat="server"
title="ReceiveContractDocumentsPageTitle"
Instruction="ContractDocumentReceptionPageInstruction"
HelpIdentifier="/Contracts/DocumentManagement/Reception.aspx"
ExitPage="/Main.aspx"
/>
   

</asp:Content>

<asp:Content ID="FormTypeCaptionContent" ContentPlaceHolderID="FormTypeCaptionPlaceHolder" Runat="Server">
<asp:Label Runat=Server id="FormTypeCaption" CssClass="Normal" Text='<%$ Resources:Strings, FormTypeCaption %>'></asp:Label>
</asp:Content>

<asp:Content ID="FormTypesContent" ContentPlaceHolderID="FormTypesPlaceHolder" Runat="Server">
<asp:ObjectDataSource
id="ContractDocumentTypesDataSource"
runat="server"
selectmethod="FindAll"
typename="Saler.Business.ContractDocumentType"
>
</asp:ObjectDataSource>
<asp:dropdownlist id="FormTypes" runat="server" CssClass="Normal" DataSourceID="ContractDocumentTypesDataSource" DataValueField="Key" DataTextField="Description"></asp:dropdownlist>
</asp:Content>

 

Here is the contents of Master Page file: 

<%@ Master Language="C#" CompileWith="Reception.master.cs" MasterPageFile="~/Masters/Interior.master" ClassName="Reception_master" %>

<asp:Content ContentPlaceHolderID="HeaderControlPlaceHolder" Runat="Server">
<asp:contentplaceholder id="HeaderControlPlaceHolder" runat="server">
</asp:contentplaceholder>
</asp:Content>

<asp:Content ID="InteriorContent" ContentPlaceHolderID="InteriorContentPlaceHolder" Runat="Server">

<table cellSpacing="0" cellPadding="4" border="0">
<tr>
<td align="right"><asp:ContentPlaceHolder id="FormTypeCaptionPlaceholder" runat="Server"></asp:ContentPlaceHolder></td>
<td><asp:ContentPlaceHolder id="FormTypesPlaceholder" runat="server"></asp:ContentPlaceHolder></td>
</tr>
<tr>
<td style="HEIGHT: 32px" align="right"><asp:ContentPlaceHolder id="SerialNumberStartCaptionPlaceholder" runat="Server"></asp:ContentPlaceHolder></td>
<td style="HEIGHT: 32px"><asp:ContentPlaceHolder id="SerialNumberStartRangePlaceholder" runat="Server"></asp:ContentPlaceHolder></td>
</tr>
<tr>
<td align="right"><asp:ContentPlaceHolder ID="SerialNumberEndRangeCaptionPlaceholder" Runat="Server"></asp:ContentPlaceHolder></td>
<td><asp:ContentPlaceHolder ID="SerialNumberRangeEndPlaceholder" Runat="Server"></asp:ContentPlaceHolder></td>
</tr>
<tr>
<td align="right"><asp:ContentPlaceHolder ID="QuantityCaptionPlaceholder" Runat="Server"></asp:ContentPlaceHolder></TD>
<td><span id="QuantityLabel"><span class="Normal">0</span></span></td>
</tr>
<tr>
<td align="right"><asp:ContentPlaceHolder ID="DateReceivedCaptionPlaceHolder" Runat="Server"></asp:ContentPlaceHolder></td>
<td><asp:ContentPlaceHolder ID="ReceptionDatePlaceholder" Runat="server"></asp:ContentPlaceHolder></td>
</tr>
</table>

<table cellSpacing="0" cellPadding="4" align="center" border="0">
<TR>
<TD><a id="ClientAddButton" HREF="javascript:ClientAddButton_OnClick()"><IMG src="/images/Saler/AddRange.gif" width="96" height="15" border="0"></a></TD>
</TR>
</table>

   

</asp:Content>

 

And the content of the Master's Master:

<%@ Master Language="C#" CompileWith="Interior.master.cs" ClassName="Interior_master" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "https://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="https://www.w3.org/1999/xhtml" >
<head runat="server">
<link rel="STYLESHEET" type="text/css" href="/Styles/Saler/Basic.css" />
<title>Interior Master Page</title>

</head>
<body>
<form id="InteriorForm" name="InteriorForm" runat="server">
<table cellSpacing="0" cellPadding="0" width="100%" border="0">
<tr>
<td>
<asp:contentplaceholder id="HeaderControlPlaceHolder" runat="server">
</asp:contentplaceholder>
</td>
</tr>
</table>
<table cellSpacing="0" cellPadding="4" width="100%" border="0">
<tr>
<td class="ColouredBackground"><span class="BoldAgainstColouredBackground"><asp:Label Runat="Server" ID="DataEntryCaption" text='<%$ Resources:Strings, DataEntryCaption %>'></asp:Label></span></td>
<td class="ColouredBackground" align="Right">
<asp:linkbutton CssClass="ColouredBackground" id="ExitButton" visible="false" Runat="server" OnClick="ExitButton_Click">
<img src="/images/Saler/greenexitbutton.gif" border="0">
</asp:linkbutton>
</td>
</tr>
</table>
<br />
<asp:contentplaceholder id="InteriorContentPlaceHolder" runat="server">
</asp:contentplaceholder>
<table cellSpacing="0" cellPadding="0" width="100%" border="0">
<tr>
<td align="right" colSpan="2">&nbsp;</td>
</tr>
<tr bgColor="#006633">
<td align="right" width="98%"><A href="#Top" class="Link">Back To Top</A></td>
<td align="right" width="2%"><IMG height="20" src="/images/Saler/bottomCorner.gif" width="16"></td>
</tr>
</table>
</form>
</body>
</html>