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="http://www.w3.org/1999/xhtml" > < 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="http://www.w3.org/1999/xhtml" > < 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="http://www.w3.org/1999/xhtml" > < 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 . into a single instance. Listing 5- 16 illustrates how to assign the master page programmatically from the content page. 251 Evjen c 05. tex V2 - 01/28/2008 12:47pm Page 252 Chapter 5: Working with. runat="server" > < title > Reuters < /title > Continued 2 53 Evjen c 05. 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. 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 < %@