Evjen c05.tex V2 - 01/28/2008 12:47pm Page 245
Chapter 5: Working with Master Pages
runat="server"
>
<
b
>
Your GUID number from the master page is:
<
br /
>
<
asp:Label ID="Label1" runat="server" /
><
/b
><
p
>
<
b
>
Enter your name:
<
/b
><
br /
>
<
asp:Textbox ID="TextBox1" runat="server" /
>
<
br /
>
<
br /
>
<
asp:Button ID="Button1" runat="server" Text="Submit"
OnClick="Button1_Click" /
><
br /
>
<
br /
>
<
asp:Label ID="Label2" runat="server" Font-Bold="True" /
>
<
/asp:Content
>
<
asp:Content ID="Content3" ContentPlaceHolderId="ContentPlaceHolder2"
runat="server"
>
<
asp:Image ID="Image1" runat="server" ImageUrl="Wrox.gif" /
>
<
/asp:Content
>
C#
<
%@ Page Language="C#" MasterPageFile="~/wrox.master" %
>
<
script runat="server"
>
protected void Page_LoadComplete(object sender, EventArgs e)
{
Label1.Text = (Master.FindControl("Label1") as Label).Text;
}
protected void Button1_Click(object sender, EventArgs e)
{
Label2.Text = "
<
b
>
Hello " + TextBox1.Text + "!
<
/b
>
";
}
<
/script
>
In this example, the master page in Listing 5-8 first creates a GUID that it stores as a text value in a Label
server control on the master page itself. The
ID
of this Label control is
Label1
. The master page generates
this GUID only on the first request for this particular content page. From here, you then populate one of
the content page’s controls with this value.
The interesting thing about the content page is that you put code in the
Page_LoadComplete
event han-
dler so that you can get at the GUID value that is on the master page. This new event in ASP.NET fires
immediately after the
Page_Load
event fires. Event ordering is covered later, but the
Page_Load
event
in the content page always fires before the
Page_Load
event in the master page. In order to get at the
newly created GUID (if it is created in the master page’s
Page_Load
event), you have to get the GUID in
an event that comes after the
Page_Load
event — and that is where the
Page_LoadComplete
comes into
play. Therefore, within the content page’s
Page_LoadComplete
event, you populate a Label server control
within the content page itself. Note that the Label control in the content page has the same
ID
as the Label
control in the master page, but this doesn’t make a difference. You can differentiate between them with
the use of the
Master
property.
Not only can you get at the server controls that are in the master page in this way, you can get at any cus-
tom properties that the master page might expose as w ell. Look at the master page shown in Listing 5-10;
it uses a custom property for the
<
h1
> section of the page.
245
Evjen c05.tex V2 - 01/28/2008 12:47pm Page 246
Chapter 5: Working with Master Pages
Listing 5-10: A master page that exposes a custom property
VB
<
%@ Master Language="VB" %
>
<
script runat="server"
>
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
If Not Page.IsPostBack Then
Label1.Text = Guid.NewGuid().ToString()
End If
End Sub
Dim m_PageHeadingTitle As String = "My Company"
Public Property PageHeadingTitle() As String
Get
Return m_PageHeadingTitle
End Get
Set(ByVal Value As String)
m_PageHeadingTitle = Value
End Set
End Property
<
/script
>
<
html xmlns=" />>
<
head id="Head1" runat="server"
>
<
title
>
My Company Master Page
<
/title
>
<
asp:ContentPlaceHolder id="head" runat="server"
>
<
/asp:ContentPlaceHolder
>
<
/head
>
<
body
>
<
form id="Form1" runat="server"
>
<
table cellpadding="3" border="1"
>
<
tr bgcolor="silver"
>
<
td colspan="2"
>
<
h1
><
%= PageHeadingTitle %
><
/h1
>
<
b
>
User’s GUID:
<
asp:Label ID="Label1" runat="server" /
><
/b
>
<
/td
>
<
/tr
>
<
tr
>
<
td
>
<
asp:ContentPlaceHolder ID="ContentPlaceHolder1"
runat="server"
>
<
/asp:ContentPlaceHolder
>
<
/td
>
<
td
>
<
asp:ContentPlaceHolder ID="ContentPlaceHolder2"
runat="server"
>
<
/asp:ContentPlaceHolder
>
<
/td
>
<
/tr
>
<
tr
>
246
Evjen c05.tex V2 - 01/28/2008 12:47pm Page 247
Chapter 5: Working with Master Pages
<
td colspan="2"
>
Copyright 2008 - My Company
<
/td
>
<
/tr
>
<
/table
>
<
/form
>
<
/body
>
<
/html
>
C#
<
%@ Master Language="C#" %
>
<
script runat="server"
>
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
Label1.Text = System.Guid.NewGuid().ToString();
}
}
string m_PageHeadingTitle = "My Company";
public string PageHeadingTitle
{
get
{
return m_PageHeadingTitle;
}
set
{
m_PageHeadingTitle = value;
}
}
<
/script
>
In this master page example, the master page is exposing the property you created called
PageHead-
ingTitle
. A default value of
"My Company"
is assigned to this property. You then place it within the
HTML of the master page file between some
<
h1
> elements. This makes the default value become the
heading used on t he page within the master page template. Although the master page already has a
value it uses for the heading, any content page that is using this master page can override the
<
h3
> title
heading. The process is shown in Listing 5-11.
Listing 5-11: A content page that overrides the property from the master page
VB
<
%@ Page Language="VB" MasterPageFile="~/Wrox.master" %
>
<
%@ MasterType VirtualPath="~/Wrox.master" %
>
<
script runat="server"
>
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
Continued
247
Evjen c05.tex V2 - 01/28/2008 12:47pm Page 248
Chapter 5: Working with Master Pages
Master.PageHeadingTitle = "My Company-Division X"
End Sub
<
/script
>
C#
<
%@ Page Language="C#" MasterPageFile="~/Wrox.master" %
>
<
%@ MasterType VirtualPath="~/Wrox.master" %
>
<
script runat="server"
>
protected void Page_Load(object sender, EventArgs e)
{
Master.PageHeadingTitle = "My Company-Division X";
}
<
/script
>
From the content page, you can assign a value to the property that is exposed from the master page by
the use of the
Master
property. As you can see, this is quite simple to do. Remember that not only can you
get at any public properties that the master page might expose, but you can also retrieve any methods
that the master page contains as well.
The item that makes this all possible is the use of the
MasterType
page directive. The
MasterType
direc-
tive allows you to make a strongly typed reference to the master page and allows you to access the master
page’s properties via the
Master
object.
Earlier, we showed you how to get at the server controls that are on the master page by using the
Find-
Control()
method. The
FindControl()
method works fine, but it is a late-bound approach, and as such,
the method call may fail if the control was removed from markup. Use defensive coding practices and
always check for null when returning objects from
FindControl()
. Using the mechanics just illustrated
(with the use of public properties shown in Listing 5-10), you can use another approach to expose any
server controls on the master page. You may find this approach to be more effective.
To do this, you simply expose the server control as a public property, as shown in Listing 5-12.
Listing 5-12: Exposing a server control from a master page as a public property
VB
<
%@ Master Language="VB" %
>
<
script runat="server"
>
Public Property MasterPageLabel1() As Label
Get
Return Label1
End Get
Set(ByVal Value As Label)
Label1 = Value
End Set
End Property
<
/script
>
248
Evjen c05.tex V2 - 01/28/2008 12:47pm Page 249
Chapter 5: Working with Master Pages
C#
<
%@ Master Language="C#" %
>
<
script runat="server"
>
public Label MasterPageLabel1
{
get
{
return Label1;
}
set
{
Label1 = value;
}
}
<
/script
>
In this case, a public property called
MasterPageLabel1
provides access to the Label control that uses
the
ID
of
Label1
. You can now create an instance of the
MasterPageLabel1
property on the content page
and override any of the attributes of the Label server control. So if you want t o increase the size of the
GUID that the master page creates and displays in the
Label1
server control, you can simply override
the
Font.Size
attribute of t he Label control, as shown in Listing 5-13.
Listing 5-13: Overriding an attribute from the Label control that is on the master page
VB
<
%@ Page Language="VB" MasterPageFile="~/Wrox.master" %
>
<
%@ MasterType VirtualPath="~/Wrox.master" %
>
<
script runat="server"
>
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
Master.MasterPageLabel1.Font.Size = 25
End Sub
<
/script
>
C#
<
%@ Page Language="C#" MasterPageFile="~/Wrox.master" %
>
<
%@ MasterType VirtualPath="~/Wrox.master" %
>
<
script runat="server"
>
protected void Page_Load(object sender, EventArgs e)
{
Master.MasterPageLabel1.Font.Size = 25;
}
<
/script
>
This approach may be the most effective way to get at any server controls that the master page exposes
to the content pages.
249
Evjen c05.tex V2 - 01/28/2008 12:47pm Page 250
Chapter 5: Working with Master Pages
Specifying Default Content
in the Master Page
As you have seen, the master page enables you to specify content areas that the content page can use.
Master pages can consist of just one content area, or they can b e made up of multiple content areas. The
nice thing about content areas is that when you create a master page, you can specify default content for
the content area. This default content can then be left in place and utilized by the content page if you
choose not to override it. Listing 5-14 shows a master page that specifies some default content within a
content area.
Listing 5-14: Specifying default content in the master page
<
%@ Master Language="VB" %
>
<
html xmlns=" />>
<
head runat="server"
>
<
title
>
My Company
<
/title
>
<
asp:ContentPlaceHolder id="head" runat="server"
>
<
/asp:ContentPlaceHolder
>
<
/head
>
<
body
>
<
form id="form1" runat="server"
>
<
asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server"
>
Here is some default content.
<
/asp:ContentPlaceHolder
><
p
>
<
asp:ContentPlaceHolder ID="ContentPlaceHolder2" runat="server"
>
Here is some more default content.
<
/asp:ContentPlaceHolder
><
/p
>
<
/form
>
<
/body
>
<
/html
>
To place default content within one of the content areas of the master page, you simply put it in the
ContentPlaceHolder
server control on the master page itself. Any content page that inherits this master
page also inherits the default content. Listing 5-15 shows a content page that overrides just one of the
content areas from this master page.
Listing 5-15: Overriding some default content in the content page
<
%@ Page Language="VB" MasterPageFile="~/MasterPage.master" %
>
<
asp:Content ID="Content3" ContentPlaceHolderId="ContentPlaceHolder2"
runat="server"
>
Here is some new content.
<
/asp:Content
>
This code creates a page with one content area that shows content coming from the master page itself, in
addition to other content that comes from the content page (see Figure 5-10).
The other interesting point when you work with content areas in the design mode of Visual Studio 2008
is that the smart tag allows you to work easily with the default content.
250
Evjen c05.tex V2 - 01/28/2008 12:47pm Page 251
Chapter 5: Working with Master Pages
Figure 5-10
When you first start working with the content page, you will notice that all the default content is at first
populated in all the Content server controls. You can change the content b y clicking on the control’s
smart tag and selecting the Create Custom Content option from the provided menu. This option enables
you to override the master page content and insert your own defined content. After you have placed
some custom content inside the content area, the smart tag shows a different option — Default to Mas-
ter’s Content. This option enables you to return the default content that the master page exposes to the
content area and to erase whatever content you have already placed in the content area — thereby sim-
ply returning to the default content. If you choose this option, you will be warned that you are about to
delete any custom content you placed within the Content server control (see Figure 5-11).
Figure 5-11
After changing one of the Content control’s default content, you might be presented with something like
Figure 5-12.
Programmatically Assigning the Master Page
From any content page, you can easily assign a master page programmatically. You assign the mas-
ter page to the content page using the
Page.MasterPageFile
property. This can be used regardless of
whether another master page is already assigned in the
@Page
directive.
To accomplish this, you use this property through the
PreInit
event. The
PreInit
event is the earliest
point in which you can access the Page lifecycle. For this reason, this is where you need to assign any
master page that is used by any content pages. The
PreInit
is an important event to make note of when
you are working with master pages, as this is the only point where you can affect both the master and
content page before they are combined into a single instance. Listing 5-16 illustrates how to assign the
master page programmatically from the content page.
251
Evjen c05.tex V2 - 01/28/2008 12:47pm Page 252
Chapter 5: Working with Master Pages
Figure 5-12
Listing 5-16: Using Page_PreInit to assign the master page programmatically
VB
<
%@ Page Language="VB" %
>
<
script runat="server"
>
Protected Sub Page_PreInit(ByVal sender As Object, ByVal e As System.EventArgs)
Page.MasterPageFile = "~/MyMasterPage.master"
End Sub
<
/script
>
C#
<
%@ Page Language="C#" %
>
<
script runat="server"
>
protected void Page_PreInit(object sender, EventArgs e)
{
Page.MasterPageFile = "~/MyMasterPage.master";
}
<
/script
>
252
Evjen c05.tex V2 - 01/28/2008 12:47pm Page 253
Chapter 5: Working with Master Pages
In this case, when the page is dynamically being generated, the master page is assigned to the content
page in the beginning of the page construction process. It is important to note that the co ntent page must
have the expected Content controls; otherwise an error is thrown.
Nesting Master Pages
I hope you see the power that master pages provide to help you create templated Web applications. So
far, you have b een creating a single master page that the content page can use. Most companies and
organizations, however, are not just two layers. Many divisions and groups exist within the organization
that might want to use variations of the master by, in effect, having a master page within a master page.
With ASP.NET, this is quite possible.
For example, imagine that Reuters is creating a master page to be used throughout the entire company
intranet. Not only does the Reuters enterprise want to implement this master page company-wide, but
various divisions within Reuters also want to provide templates for the subsections of the intranet
directly under their control. Reuters Europe and Reuters America, for example, each wants its own
unique master page, as illustrated in Figure 5-13.
Figure 5-13
To do this, the creators of the Reuters Europe and Reuters America master pages simply create a master
page that inherits from the global master page, as illustrated in Listing 5-17.
Listing 5-17: The main master page
ReutersMain.master
<
%@ Master Language="VB" %
>
<
html xmlns=" />>
<
head runat="server"
>
<
title
>
Reuters
<
/title
>
Continued
253
Evjen c05.tex V2 - 01/28/2008 12:47pm Page 254
Chapter 5: Working with Master Pages
<
asp:ContentPlaceHolder id="head" runat="server"
>
<
/asp:ContentPlaceHolder
>
<
/head
>
<
body
>
<
form id="form1" runat="server"
>
<
p
><
asp:Label ID="Label1" runat="server" BackColor="LightGray"
BorderColor="Black" BorderWidth="1px" BorderStyle="Solid"
Font-Size="XX-Large"
>
Reuters Main Master Page
<
/asp:Label
><
/p
>
<
asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server"
>
<
/asp:ContentPlaceHolder
>
<
/form
>
<
/body
>
<
/html
>
This is a simple master page, but excellent for showing you how this nesting capability works. The main
master page is the master page used globally in the company. It has the ContentPlaceHolder server
control with the
ID
of
ContentPlaceHolder1
.
When you create a submaster or nested master page, you accomplish this task in the same manner as
you would when building any other master page. From the Add New Item dialog, select the Master Page
option and make sure you have the Select master page option selected, as illustrated in Figure 5-14. This
will take you again to the dialog that will allow you to make a master page selection.
Figure 5-14
254