Pages

Advertisement

Wednesday, July 11, 2007

An In-Depth Coverage of ASP.NET 2.0's Master Pages: Part 2 of 3

Specifying a Master Page

You can specify the master page for a content page in two different ways:

  1. At the page level: In the content page's @Page directive, you can specify the master page. This is the method used when you create a content page through Visual Studio. A sample page directive is:
    <%@ Page MasterPageFile="~/MySite.master". %>

    Note: ASP.NET resolves the ~ operator to the root of the current application. The ~ operator can be used only in server controls; you cannot use the ~ operator for client elements (that is, HTML elements without the runat="server" specified).


  2. At the application or folder level: You also can specify the master page to use for content pages in the web.config file. For this, use the web.config file's pages element's masterPageFile attribute. By using this method, one can specify in one place the master page for all the content pages in the Web site or in a particular folder. A sample setting is:
    <configuration>
    <system.web>
    <pages masterPageFile="~/MySite.master" />
    </system.web>
    </configuration>


  3. Note: If you have specified the master page file to use in the web.config file and also at the page level in the @Page directive, the page setting overrides the web.config setting.


Nested Master Pages

Master pages can be nested; for example, a content page refers to a master page which in turn uses another master page. In a typical Web site, the pages are divided into sections; for example, an admin section and a user section. All pages have some common UI that is common for the full Web site. Each section has some UI that is shared just by pages in that section. One can design for this scenario by using nested master pages. The UI common to the full Web site can be put into a parent master page, while each section can have a separate master page that inherits from the parent master page. A sample application is included with this article; it uses nested master pages.

Accessing Controls on the Master Page

You might need to programmatically access the controls on the master page from content page code. The Page class has a property called Master which, at runtime, references the page's master page, if it has one. But, because the controls are added as protected members, you cannot access them directly using the Master property; use the FindControl method to reference them.

The following code in the content page's code-behind file shows an example of using FindControl:

Visual Basic

' Gets a reference to a Label control ("masterPageLabel")
' on the master page
Dim mpLabel As Label
mpLabel = CType(Master.FindControl("masterPageLabel"), Label)
If Not mpLabel Is Nothing Then
'Set content page title to master page control
Title.Text = mpLabel.Text
End If

C#

// Gets a reference to a Label control ("masterPageLabel")
// on the master page
Label mpLabel = (Label) Master.FindControl("masterPageLabel");
if(mpLabel != null)
{
//Set content page title to master page control
Title.Text = mpLabel.Text
}

Note: Master pages can contain ContentPlaceHolder controls that contains default content. If you want to get a reference to a control that is inside a ContentPlaceHolder control, first get a reference to the ContentPlaceHolder control and then use its FindControl method. Also, note that if the ContentPlaceHolder contents are overridden by the content page, the controls in ContentPlaceHolder control will not be accessible.


Accessing Methods and Properties of the Master Page

Master pages not only contain controls but can also contain methods and properties too. You can access these by using the Master property of the content page's Page class.

The Master property is defined in this way:

Visual Basic

Public ReadOnly Property Master As MasterPage

C#

public MasterPage Master { get; }

Here, MasterPage is the base class of your master page. To use this property, you can either type-cast it to your master page's class or use the @MasterType directive in the content page. When you use the @MasterType directive, the master page's public members can be directly accessed from the Master property as shown below:

Here, Home.aspx is the content page (notice the @MasterPage directive). The master page has a public property called MpProperty:

Home.aspx

<%@ Page MasterPageFile="~/SiteMaster.master"
CodeFile="Home.aspx.cs"
Inherits="Home" %>
<%@ MasterType VirtualPath="~/SiteMaster.master" %>

Home.aspx.cs

this.Title = Master.MpProperty;    // No type-casting required.

Note: If you set the content page to use a particular master page and you set the @MasterPage directive to a totally different master page class, at runtime you will get an InvalidCastException error.


A sample application for accessing master page controls and methods and properties is included.

Setting Master Page Programmatically

As you have already seen, you can specify a content page's master page at design time in its @Page directive or in the web.config file. What if you want to set the master page to use at runtime? One might want to change the look of the Web site at runtime if, say, the Web site integrates into different portals or if for different users you present a different look for the Web site. This could be a common requirement.

As the master page is merged into the content page at the page initialization stage, you need to specify the master page in the content page's PreInit event. This event occurs before the page's Load event. Sample code is shown below.

Visual Basic

Sub Page_PreInit(ByVal sender As Object, _
ByVal e As EventArgs) Handles Me.PreInit
Me.MasterPageFile = "~/NewMaster.master"
End Sub

C#

void Page_PreInit(Object sender, EventArgs e)
{
this.MasterPageFile = "~/NewMaster.master";
}

Referencing External Resources

At runtime, the master page merges into the content page and runs in the context of the content page. Now, the question that arises is that if you specify a path on the master page, say the UEL of an image, is this path resolved relative to the location of the master page or the content page? Consider an ASP.NET application with a master page and two content pages that are in different locations as shown.


Figure 1: A Web application in which content pages are in different locations with respect to the master page.

There are two different ways in which paths are handled in master pages:


  1. Server controls: In server controls on master pages, ASP.NET modifies the URLs of properties that reference external resources. For example, in the above application, if you have an Image Web control on the master page SiteMaster.master and you set its ImageUrl property to "Images/logo.jpg" at runtime ASP.NET will modify the URL so that it resolves correctly in the context of the content page. The behavior is summarized below.

    Code in SiteMaster.aspx:

       <asp:Image ID="Image1"
    runat="server"
    ImageUrl="Images/logo.jpg" />

    Runtime rendering for Home.aspx:

    <img ID="Image1" src="Images/logo.jpg" />

    Runtime rendering for AdminTest.aspx:

    <img ID="Img1" src="../Images/logo.jpg" />

    Result: Image renders just fine for both Home.aspx and AdminTest.aspx.


  2. Plain html: If you have plain HTML elements (that is, HTML controls without the runat="server" specified) on the master page, ASP.NET does not modify this and passes it on as is. This can create problems. For example, consider a plain HTML img on the master page as shown.

Code in SiteMaster.aspx:

<img ID="Image2" src="Images/logo.jpg" />

Runtime rendering for Home.aspx:

<img ID="Img2" src="Images/logo.jpg" />

Runtime rendering for AdminTest.aspx:

<img ID="Img3" src="Images/logo.jpg" />

Result: Image shows up in Home.aspx but not for AdminTest.aspx because the path is incorrect.

If you face the problem of paths on a master page not resolving properly when merging with content pages, you have the following options:


  1. Instead of using plain HTML, use server controls. You can do this by using corresponding Web server controls or by putting runat="server" in the plain HTML, thereby making them HTML server controls. So, in the above example you could change the plain img tags to
    <asp:Image ID="Image1" ImageUrl="Images/logo.jpg"
    runat="server" />

    OR

    <img ID="Img4" src="Images/logo.jpg" runat="server" >

    Note: Using this approach is going to lead to a small performance hit because server controls take a little more processing time.


  2. In the master page, for the plain HTML elements, instead of using a relative path, give the full path. This method doesn't result in a performance hit but the drawback here is that it's not a good idea to hardcode the URLs to the full path. So, in the example, the img would be specified as
    <img ID="Img5"
    src="http://www.mywebsite.com/Images/logo.jpg" >

  3. Keep your file layout in such a way that the content pages have the same relative position to the master page.

Some Useful Links


  1. This book has a great chapter on master pages (you can download this chapter for free!)
    A First Look at ASP.NET v 2.0
  2. The master pages section on ASP.NET Web
    Visual Web Developer 2005 Express Edition Beta Guided Tour

No comments:

Post a Comment