Master Pages: Beyond the Basics

Master ASP.NET Pages and Take Advantage of a Rich Layout

CoreCoder

LANGUAGES: C#

ASP.NET VERSIONS: 2.0

 

Master Pages: Beyond the Basics

Master ASP.NET Pages and Take Advantage of a Rich Layout

 

By Dino Esposito

 

ASP.NET 2.0 introduced master pages as a way to simplify the creation of pages with a similar layout and look-and-feel. A page bound to a master is partitioned in regions. All regions are defined in the context of a static layout and represent the variable portion of an otherwise static page. An ASP.NET page based on a master page provides a final layout that is like the master page, except for the contents of a few replaceable regions.

 

After a quick refresher, I ll explore some advanced capabilities of master pages and their use in ASP.NET AJAX applications. In particular, I ll focus on how to dynamically define a master page, how to give the master a programmable object model, and nested master pages.

 

A Quick Refresher

A master page is a file with a .master extension whose internal syntax looks like a regular ASP.NET page. A master page defines the overall layout of all pages derived from it. A page derived from a master page is said to be a content page. The master is characterized by an @Master directive and a few content placeholder tags. Each <asp:contentplaceholder> tag identifies a region in the page that can be customized by the content page. In general, a multitude of pages derive from a given master; all derived pages share the same overall layout, but differ in the contents that each page displays in the various placeholders defined on the master.

 

The master page file remains invisible to end-users; the endpoint that users connect to through their browser is the URL of the content page. At compile time, ASP.NET takes care of combining the master page layout with the actual contents that the page provides for each customizable region. Figure 1 shows a sample master page and a derived content page.

 

<%@ Master Language="C#" CodeFile="Simple.master.cs"

 Inherits="Simple" %>

<html>

<head runat="server">

 <title>Master page</title>

</head>

<body>

  <form id="form1" runat="server">

    <asp:Panel ID="HeaderPanel" runat="server" Width="100%">

        <asp:Label ID="Caption" runat="server"

          Text="Master" />

    </asp:Panel>

    <asp:contentplaceholder id="Body" runat="server">

      <%-- A content page shall define the contents

       to show here --%>

      <h1>This is the default content</h1>

    </asp:contentplaceholder>

    <asp:Panel ID="FooterPanel" runat="server">

         <asp:Label ID="Footer" runat="server"

          Text="written with ASP.NET" />

    </asp:Panel>    

  </form>

</body>

</html>

<%@ Page Language="C#" MasterPageFile="Simple.master"

      CodeFile="Hello.aspx.cs" Inherits="Hello" %>

<asp:Content ID="Content1" ContentPlaceHolderID="Body"

 runat="server">

  <h1>Welcome to this page!</h1>

</asp:Content>

Figure 1: A sample master and content page.

 

The master page in Figure 1 defines one placeholder named Body, and surrounds it with a couple of panels. Obviously, each content placeholder must have a unique ID and can optionally have default contents. The default contents, if any, are shown only in case the derived page doesn t override the placeholder s contents.

 

A content page has a very special structure for being a regular ASP.NET page invoked from the client. In fact, it can only contain <asp:Content> tags and the @Page directive. Any other type of source tags would generate a compile error. A content tag is given an ID that matches the ID of one of the placeholders in the master. The association between a content page and its master is set in the @Page directive of the content page; precisely, it is handled via the MasterPageFile attribute:

 

<%@ Page Language="C#" MasterPageFile="Simple.master"

 CodeFile="Hello.aspx.cs" Inherits="Hello" %>

 

A content page may not fill all the placeholders in the master. If some placeholders are not set, they will take the default content, if any or will simply be considered empty.

 

Dynamic Master Pages

The master page defines the skeleton of the final page served to the user. If you want to share a given user interface layout among all the pages of the application, deriving pages from a master will greatly simplify the task. In other words, you first create the master and then devise all your remaining pages in terms of a delta from the master. This approach works well as long as you have only one master for any given pages. What if, instead, you don t know in advance what s the master of a given page and get to know the URL of the master page only at run time? There are at least a couple of realistic scenarios that make this issue quite concrete: skinned applications and role-based applications.

 

An application that supports skins allows individual users to display the same set of user interface elements according to a different layout. Admittedly, an ASP.NET skinned application might be implemented in a variety of ways, including in a way that makes intensive use of CSS stylesheets and perhaps the newest CSS-friendly control adapters (see http://www.asp.net/cssadapters for more information). However, one of the possible ways to code a skinned application is through dynamically set master pages. The ability to dynamically set the master page is also essential to design applications with a strong role connotation. Each user, in fact, will be automatically served a slightly different layout according to its role.

 

How would you set the master page programmatically? To be honest, this question has an easy answer. The real question to ask is, when do you set the master page dynamically? This is not a task that can be accomplished at any time. When the page begins its lifecycle, the master page, if any, must already be linked to the page. As a result, the latest moment in which you can set the master page programmatically is when the PreInit event fires. Incidentally, PreInit is also the first page-level event you can handle programmatically. The following code snippet shows how to set a master page programmatically:

 

protected void Page_PreInit(object sender, EventArgs e)

{

  this.MasterPageFile = "adminUser.master";

}

 

Note that an exception would be raised if you try to set the MasterPageFile property from within other event handlers, such as Init or Load. The URL you assign to the MasterPageFile property of the Page class must point to a valid master file. The contents of the master file are then processed and originates an instance of the MasterPage class. The Master property on the Page class represents the current instance of the master page object. The property is read-only and can t be set programmatically.

 

You should be aware that in the PreInit event no page controls have been instantiated yet; also, the viewstate is far from being analyzed and restored. However, posted values are available they come through the query string or form fields. If the name of the master is communicated over the request, you must resort to using a QueryString or Form collection to read posted values.

 

Expose an Object Model

A master page can be powered by a code-behind class and can incorporate basic code. In addition, it also can expose properties, methods, and events to content pages. Note that any controls defined in the master page markup are not by default visible from within content pages. To make a master page control visible and programmable from within a content page, you need to add code to the master page code-behind class that defines a public wrapper for that control or control property. The following code shows how to publicly expose the Text property of the Label control defined in the placeholder of Figure 1:

 

public partial class Simple : System.Web.UI.MasterPage

{

   public string Title

   {

       get { return Caption.Text; }

       set { Caption.Text = value; }

   }

}

 

The public property named Title wraps the Text property of the Label control named Caption. The Title property is defined in the class named Simple (as shown in Figure 1, the class name of the master page).

 

As previously mentioned, the current instance of the master page is exposed through the Master property of the Page class. Unfortunately, though, the Master property is defined of type MasterPage (the base type for all master page classes). Furthermore, the MasterPage class doesn t know anything about a Title property. The following code simply doesn t compile:

 

protected void Page_Load(object sender, EventArgs e)

{

  Master.Title = "Hello, aspnetPRO";

}

 

So how can you invoke custom properties and methods defined on the master? The key information that is missing here is the real type of the master page object. By knowing this type, you could cast the Master object to the right type and safely invoke any defined members. By default, the name of the master page class is determined dynamically looking at the name of the source file. However, the ClassName attribute of the @Master directive gives developers a great chance to set it to a fixed string:

 

<%@ Master Inherits="Simple" Classname="SampleMaster" ... %>

 

In light of this, you can modify the preceding code as follows:

 

protected void Page_Load(object sender, EventArgs e)

{

   ((SampleMaster)Master).Title = "Hello, aspnetPRO";

}

 

What s the purpose of a master page object model? An object model makes the master page more flexible, thus giving content pages a chance to partially modify the portions of the page left out of replaceable regions. But that s the point if you come to the conclusion that certain parts of the master can be customizable, should you opt for a content placeholder or an object model? In general, you opt for a replaceable region and therefore a placeholder if you want developers of content pages to completely modify the layout of that portion. In this way, different pages may have completely different layouts at a given location. With an object model, instead, the master page exercises a more strict control over which content pages can change in a given area. The object model gives all content pages access to certain parts of the page, but what content pages can do is limited by the object model. For example, you use an object model if you want to show a menu but want to give content pages a chance to add or remove items; you use a placeholder if you want to allow pages to replace the menu with a treeview or something else.

 

Nesting Master Pages

The master/content relationship can be made as complex as needed. In fact, a master page can be associated with another master to form a hierarchical structure. The root master page defines a number of placeholders. A first-level content page may fill some or all of the parent s placeholders and can, in turn, add new placeholders. The next level of content page can do the same, and so on. There s no physical limitation to the number of supported nesting levels.

 

A nested master page is the intermediate page, which is half a content page and half a master page. What s the structure of a nested master page? It looks like a content page, except that it contains the @Master directive instead of the @Page directive. In addition, the nested master page takes the liberty of inserting content placeholders inside its <asp:Content> tags:

 

<%@ Master Language="C#" MasterPageFile="Parent.master"

 CodeFile="Content.master.cs" Inherits="ContentMaster" %>

<asp:Content runat="server"

 contentplaceholderid="ParentRegion">

  <asp:contentplaceholder runat="server" id="ChildRegion">

    :

  </asp:contentplaceholder>

</asp:Content>

 

The preceding directive shows a master page that is bound to a parent master page. The ASP.NET runtime fully supports nested master pages; the Visual Studio 2005 designer does not. You get a friendly error message when you switch to design mode in an ASP.NET page with nested masters. Awaiting the next version of Visual Studio to fix the issue, you can apply a workaround to fool Visual Studio 2005. Scott Guthrie explains the details in the following post: http://weblogs.asp.net/scottgu/archive/2005/11/11/430382.aspx.

 

Master Pages and AJAX Applications

A Web site based on master pages is not necessarily efficient from a performance standpoint. Compared to a Web site built with traditional ASP.NET pages, the performance is nearly the same. The main advantage of master pages, therefore, is helping the developer to author pages more quickly. However, this fact alone doesn t necessarily make your site serve pages faster.

 

If the structure of the page is too heavy, every postback may become painful for the end-user. In this context, master pages are neither the answer nor the problem. Where the desired page layout can be expressed with a frameset, you can physically divide the page in distinct portions managed separately by the browser. Compared to master pages, framesets are a different thing but can be employed to minimize the impact of frequent postbacks on a complex user interface. ASP.NET AJAX is a much better answer to the need of a painless refresh. Using AJAX functionalities in pages bound to a master pose an issue that must be properly addressed.

 

As you may know, any ASP.NET AJAX page requires a unique script manager component. You might want to place this component in the master page and have all content pages inherit its services. What if, though, one particular content page needs to register with the manager a service or a script that is not relevant for all other content pages? In this case, you leave the master page intact and insert a script manager proxy in the content page:

 

<asp:Content runat="server"

 contentplaceholderid="ParentRegion">

  <asp:scriptmanagerproxy runat="server" id="Proxy1" />

</asp:Content>

 

You configure the script manager proxy as required and set it to pass its settings up to the master page script manager. The proxy is not a copy of the script manager; it is simply a piece of code that gathers extra settings and passes them on to the real and unique script manager in the page.

 

Conclusion

Master pages are not representatives of a pure object-oriented visual inheritance, such as what you get in Windows Forms. Rather, master pages are a mechanism to aggregate blocks of user interface elements in a predefined master layout. With support from the Visual Studio .NET 2005 environment, master pages are really a time-saving feature that brings concrete added-value to ASP.NET 2.0 solutions. In this article, I examined some of the advanced features applicable in real-world projects.

 

Dino Esposito is a Solid Quality Learning mentor and the author of Introducing ASP.NET 2.0 AJAX Extensions and Programming Microsoft ASP.NET 2.0-Core Reference, both from Microsoft Press. Based in Italy, Dino is a frequent speaker at industry events worldwide. Join the blog at http://weblogs.asp.net/despos.

 

 

 

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish