共用方式為


巢狀主版頁面 (VB)

由斯科特· 米切爾

示範如何將一個主版頁面巢狀於另一個主版頁面內。

簡介

在過去九個教學課程中,我們已瞭解如何使用主版頁面實作全網站版面配置。 簡言之,主版頁面可讓我們頁面開發人員定義主版頁面中的通用標記,以及可在內容頁面上逐頁自定義的特定區域。 主版頁面中的 ContentPlaceHolder 控件會指出可自定義的區域;ContentPlaceHolder 控件的自定義標記會透過內容控件定義於內容頁面中。

到目前為止所探索的主版頁面技術,如果您有在整個網站中使用的單一版面配置,就非常出色。 不過,許多大型網站都有網站版面配置,可跨各種區段自定義。 例如,請考慮醫院工作人員用來管理病患資訊、活動和帳單的醫療保健應用程式。 此應用程式中可能有三種類型的網頁:

  • 員工專屬頁面,員工可以更新可用性、檢視排程或要求休假時間。
  • 員工檢視或編輯特定病患資訊的病患特定頁面。
  • 會計會檢閱目前索賠狀態和財務報告的帳單特定頁面。

每個頁面都可能會共用一般版面配置,例如頂端的功能表,以及沿著底部的一系列常用連結。 但是員工、病患和計費特定頁面可能需要自定義此一般版面配置。 例如,也許所有員工特定頁面都應該包含行事曆和工作清單,其中顯示目前登入使用者的可用性和每日排程。 也許所有患者特定頁面都需要顯示正在編輯其資訊之患者的名稱、位址和保險資訊。

您可以使用巢狀主版頁面來建立這類自定義版面配置。 為了實作上述案例,我們會先建立主版頁面來定義全網站版面配置、功能表和頁尾內容,並定義可自定義的區域 ContentPlaceHolders。 然後,我們會建立三個巢狀主版頁面,每個類型的網頁各一個。 每個巢狀主版頁面都會在使用主版頁面的內容頁面類型中定義內容。 換句話說,患者特定內容頁面的巢狀主版頁面會包含標記和程式設計邏輯,以顯示正在編輯之患者的相關信息。 建立新的病患特定頁面時,我們會將其系結至這個巢狀主版頁面。

本教學課程一開始會醒目提示巢狀主版頁面的優點。 然後會示範如何建立和使用巢狀主版頁面。

注意

巢狀主版頁面自 .NET Framework 2.0 版以來一直可行。 不過,Visual Studio 2005 不包含巢狀主版頁面的設計時間支援。 好消息是,Visual Studio 2008 為巢狀主版頁面提供豐富的設計時間體驗。 如果您有興趣使用巢狀主版頁面,但仍使用Visual Studio 2005,請參閱 Scott Guthrie 的部落格文章: VS 2005 設計時間中巢狀主版頁面的秘訣。

巢狀主版頁面的優點

許多網站都有一個整體的網站設計,以及特定頁面類型特定的自定義設計。 例如,在我們的示範 Web 應用程式中,我們建立了一個基本的系統管理區段(資料夾中的頁面 ~/Admin )。 資料夾中的 ~/Admin 網頁目前會使用與管理區段中不同頁面的相同主版頁面(也就是 Site.masterAlternate.master,視使用者的選取專案而定)。

注意

目前,假設網站只有一個主版頁面。 Site.master 在本教學課程稍後,我們將說明使用巢狀主版頁面搭配兩個(或更多)主版頁面,從「使用管理區段的巢狀主版頁面」開始。

假設我們被要求自定義 [系統管理] 頁面的版面配置,以包含其他資訊或鏈接,否則不會出現在網站中的其他頁面中。 實作這項需求有四種技術:

  1. 手動新增系統管理特定資訊,並連結至資料夾中的每個內容頁面 ~/Admin
  2. Site.master更新主版頁面以包含 [系統管理] 區段特定資訊和鏈接,然後將程式代碼新增至主版頁面,根據其中一個系統管理頁面是否瀏覽,顯示或隱藏這些區段。
  3. 為 [系統管理] 區段建立新的主版頁面、從 複製標記 Site.master、新增 [系統管理] 區段特定資訊和鏈接,然後更新資料夾中的內容頁面 ~/Admin ,以使用這個新的主版頁面。
  4. 建立巢狀主版頁面,系結至 Site.master 資料夾中的內容頁面 ~/Admin ,並使用這個新的巢狀主版頁面。 這個巢狀主版頁面只會包含系統管理頁面特有的其他資訊和連結,而且不需要重複中 Site.master已定義的標記。

第一個選項是最不討人看得起的。 使用主版頁面的整個點,就是不需手動複製並貼上通用標記至新的 ASP.NET 頁面。 第二個選項是可接受的,但讓應用程式更容易維護,因為它會大量顯示只有偶爾顯示的標記的主版頁面,而且需要開發人員編輯主版頁面來處理此標記,而且必須記住何時、確切地顯示特定標記,而不是隱藏時。 此方法較不可行,因為這個單一主版頁面需要容納更多類型的網頁自定義。

第三個選項會移除第二個選項所呈現的雜亂和複雜度問題。 不過,選項三的主要缺點是,它要求我們複製並貼上通用版面配置,並 Site.master 貼到新的 [系統管理] 區段特定主版頁面。 如果我們稍後決定變更全網站版面配置,我們必須記得在兩個地方變更它。

第四個選項,巢狀主版頁面,給我們最好的第二和第三個選項。 全網站版面配置資訊會保留在一個檔案中,也就是最上層主版頁面,而特定區域的特定內容則會分成不同的檔案。

本教學課程從建立和使用簡單的巢狀主版頁面開始。 我們會建立全新的頂層主版頁面、兩個巢狀主版頁面和兩個內容頁面。 從「使用「管理區段的巢狀主版頁面」開始,我們探討如何更新現有的主版頁面架構,以包含使用巢狀主版頁面。 具體而言,我們會建立巢狀主版頁面,並用它來包含資料夾中內容頁面 ~/Admin 的其他自定義內容。

步驟 1:建立簡單的最上層主版頁面

根據其中一個現有的主版頁面建立巢狀主圖形,然後更新現有的內容頁面以使用這個新的巢狀主版頁面,而不是最上層主版頁面需要一些複雜度,因為現有的內容頁面已經預期最上層主版頁面中定義的特定 ContentPlaceHolder 控件。 因此,巢狀主版頁面也必須包含具有相同名稱的相同 ContentPlaceHolder 控件。 此外,我們的特定示範應用程式有兩個主版頁面(Site.masterAlternate.master),會根據使用者的喜好設定動態指派至內容頁面,進一步增加此複雜性。 我們將在本教學課程稍後探討更新現有的應用程式以使用巢狀主版頁面,但讓我們先將焦點放在簡單的巢狀主版頁面範例上。

建立名為 NestedMasterPages 的新資料夾,然後將新的主版頁面檔案新增至名為 Simple.master的資料夾。 (如需新增此資料夾和檔案之後 方案總管 的螢幕快照,請參閱圖 1。將AlternateStyles.css樣式表單檔案從 方案總管 拖曳至設計工具。 這會在 元素的樣式表單檔案中<head>新增<link>元素,之後主版頁面的<head>元素標記看起來應該像這樣:

<head runat="server"> 
 <title>Untitled Page</title> 
 <asp:ContentPlaceHolder id="head" runat="server"> 
 </asp:ContentPlaceHolder>
 <link href="../AlternateStyles.css" rel="stylesheet" type="text/css" /> 
</head>

接下來,在的 Web 窗體 Simple.master中新增下列標記:

<div id="topContent"> 
 <asp:HyperLink ID="lnkHome" runat="server" 
 NavigateUrl="~/NestedMasterPages/Default.aspx" 
 Text="Nested Master Pages Tutorial (Simple)" /> 
</div> 
<div id="mainContent"> 
 <asp:ContentPlaceHolder id="MainContent" runat="server"> 
 </asp:ContentPlaceHolder>
</div>

此標記會在海軍背景上以白色大字型顯示頁面頂端標題為「巢狀主版頁面(簡單)」的連結。 其下方是 MainContent ContentPlaceHolder。 圖 1 顯示 Simple.master Visual Studio 設計工具中載入時的主版頁面。

在 Visual Studio 設計工具中載入時,[簡單點主圖形] 主版頁面。

圖 01:巢狀主版頁面定義系統管理區段中頁面的特定內容(按兩下以檢視完整大小的影像

步驟 2:建立簡單的巢狀主版頁面

Simple.master 包含兩個 MainContent ContentPlaceHolder 控件:我們在網頁表單中新增的 ContentPlaceHolder 以及 head 元素中的 <head> ContentPlaceHolder。 如果我們要建立內容頁面,並將它系結至 Simple.master 內容頁面,則會有兩個參考 ContentPlaceHolders 的內容控制件。 同樣地,如果我們建立巢狀主版頁面並將其系結至 Simple.master ,則巢狀主版頁面會有兩個內容控件。

讓我們將新的巢狀主版頁面新增至 NestedMasterPages 名為 SimpleNested.master的資料夾。 以滑鼠右鍵按下 NestedMasterPages 資料夾,然後選擇 [新增專案]。 這會顯示圖 2 中顯示的 [新增專案] 對話方塊。 選取 [主版頁面] 範本類型,然後輸入新主版頁面的名稱。 若要指出新的主版頁面應該是巢狀主版頁面,請檢查 [選取主版頁面] 複選框。

接下來,按兩下 [新增] 按鈕。 這會顯示將內容頁面系結至主版頁面時所看到的 [選取主版頁面] 對話框(請參閱圖 3)。 選擇資料夾中的主 Simple.master 版頁面 NestedMasterPages ,然後按下 [確定]。

注意

如果您使用 Web 應用程式專案模型建立 ASP.NET 網站,而不是網站專案模型,您將不會在圖 2 所示的 [新增專案] 對話方塊中看到 [選取主版頁面] 複選框。 若要在使用 Web 應用程式專案模型時建立巢狀主版頁面,您必須選擇巢狀主版頁面範本(而不是主版頁面範本)。 選取巢狀主版頁面範本並按兩下 [新增] 之後,如圖 3 所示的 [選取主版頁面] 對話框隨即出現。

核取 [選取主版頁面] 複選框以新增巢狀主版頁面

圖 02:核取 [選取主版頁面] 複選框以新增巢狀主版頁面(按兩下以檢視完整大小的影像

將巢狀主版頁面系結至 Simple.master 主版頁面

圖 03:將巢狀主版頁面系結至 Simple.master 主版頁面(按兩下以檢視完整大小的影像

如下所示的巢狀主版頁面宣告式標記包含兩個參考最上層主版頁面的 ContentPlaceHolder 控件的內容控制項。

<%@ Master Language="VB" MasterPageFile="~/NestedMasterPages/Simple.master" AutoEventWireup="false" CodeFile="SimpleNested.master.vb" Inherits="NestedMasterPages_SimpleNested" %> 
 <asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server"> 
 </asp:Content> 
 <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" Runat="Server"> 
 </asp:Content>

<%@ Master %>除了指示詞之外,巢狀主版頁面的初始宣告式標記與將內容頁面系結至相同最上層主版頁面時最初產生的標記相同。 如同內容頁面的 <%@ Page %> 指示詞, <%@ Master %> 這裡的 指示詞包含屬性 MasterPageFile ,指定巢狀主版頁面的父主版頁面。 巢狀主版頁面與系結至相同最上層主版頁面的內容頁面主要差異在於巢狀主版頁面可以包含 ContentPlaceHolder 控件。 巢狀主版頁面的 ContentPlaceHolder 控件會定義內容頁面可以自定義標記的區域。

更新這個巢狀主版頁面,使其在對應至 MainContent ContentPlaceHolder 控件的內容控件中顯示 “Hello, from SimpleNested!” 文字。

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" Runat="Server"> 
 <p>Hello, from SimpleNested!</p>
</asp:Content>

新增之後,請儲存巢狀主版頁面,然後將新的內容頁面新增至 NestedMasterPages 名為 Default.aspx的資料夾,並將它系結至 SimpleNested.master 主版頁面。 新增此頁面時,您可能會驚訝地看到它不包含任何內容控件(請參閱圖 4)! 內容頁面只能存取其 主版頁面的 ContentPlaceHolders。 SimpleNested.master 不包含任何 ContentPlaceHolder 控件;因此,系結至此主版頁面的任何內容頁面都不能包含任何內容控件。

新的內容頁面不包含任何內容控制件

圖 04:新增內容頁面不包含任何內容控制件(按兩下以檢視完整大小的影像

我們需要做的是更新巢狀主版頁面 (SimpleNested.master) 以包含 ContentPlaceHolder 控件。 一般而言,您希望巢狀主版頁面包含其父主版頁面所定義之每個 ContentPlaceHolder 的 ContentPlaceHolder,讓其子主版頁面或內容頁面能夠與任何最上層主版頁面的 ContentPlaceHolder 控件搭配使用。

SimpleNested.master更新主版頁面,使其兩個 Content 控件中包含 ContentPlaceHolder。 為 ContentPlaceHolder 控制項提供與其 ContentPlaceHolder 控件所參照之 ContentPlaceHolder 控件相同的名稱。 也就是說,將名為 MainContent 的 ContentPlaceHolder 控件新增至 中SimpleNested.masterMainContent參考 ContentPlaceHolder 的 Simple.masterContentPlaceHolder 控件。 在參考 head ContentPlaceHolder 的 Content 控件中執行相同動作。

注意

雖然我建議將巢狀主版頁面中的 ContentPlaceHolder 控件命名為與最上層主版頁面中的 ContentPlaceHolders 相同,但不需要此命名對稱性。 您可以在巢狀主版頁面中提供 ContentPlaceHolder 控件任何您想要的名稱。 不過,如果我的最上層主版頁面和巢狀主版頁面使用相同的名稱,我發現更容易記住 ContentPlaceHolders 與頁面哪些區域對應。

進行這些新增之後,主 SimpleNested.master 版頁面的宣告式標記看起來應該如下所示:

<%@ Master Language="VB" MasterPageFile="~/NestedMasterPages/Simple.master" AutoEventWireup="false" CodeFile="SimpleNested.master.vb" Inherits="NestedMasterPages_SimpleNested" %> 
 <asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server"> 
 <asp:ContentPlaceHolder ID="head" runat="server"> 
 </asp:ContentPlaceHolder>
 </asp:Content> 
 <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" Runat="Server"> 
 <p>Hello, from SimpleNested!</p>
 <asp:ContentPlaceHolder ID="MainContent" runat="server"> 
 </asp:ContentPlaceHolder>
 </asp:Content>

Default.aspx刪除我們剛才建立的內容頁面,然後重新新增它,並將它系結至SimpleNested.master主版頁面。 這次 Visual Studio 會將兩個 Content 控件新增至 Default.aspx,參考現在定義的 SimpleNested.master ContentPlaceHolders (請參閱圖 6)。 在參考 MainContent的內容控件中,新增 “Hello, from Default.aspx!” 文字。

圖 5 顯示此處涉及的三個實體 - Simple.masterSimpleNested.masterDefault.aspx - 以及它們彼此的關聯性。 如圖所示,巢狀主版頁面會為其父系的 ContentPlaceHolder 實作 Content 控件。 如果這些區域必須可供內容頁面存取,巢狀主版頁面必須將自己的 ContentPlaceHolders 新增至 Content 控制件。

最上層和巢狀主版頁面會指定內容頁面的版面配置

圖 05:最上層和巢狀主版頁面指定內容頁面的版面配置(按兩下以檢視完整大小的影像

此行為說明內容頁面或主版頁面如何只辨識其父主版頁面。 Visual Studio 設計工具也會指出此行為。 圖 6 顯示 的設計工具 Default.aspx。 雖然設計工具清楚顯示哪些區域可從內容頁面編輯,哪些部分不是,但不會釐清巢狀主版頁面有哪些不可編輯的區域,以及哪些區域來自最上層主版頁面。

內容頁面現在包含巢狀主版頁面 ContentPlaceHolders 的內容控件

圖 06:內容頁面現在包含巢狀主版頁面 ContentPlaceHolders 的內容控件(按兩下以檢視完整大小的影像

步驟 3:新增第二個簡單巢狀主版頁面

當有多個巢狀主版頁面時,巢狀主版頁面的優點更為明顯。 為了說明這項優點,請在 NestedMasterPages 資料夾中建立另一個巢狀主版頁面;將這個新的巢狀主版頁面 SimpleNestedAlternate.master 命名為 ,並將其系結至 Simple.master 主版頁面。 在巢狀主版頁面的兩個內容控件中新增 ContentPlaceHolder 控件,就像我們在步驟 2 中所做的一樣。 此外,在對應至最上層主版頁面 ContentPlaceHolder 的內容控件中,新增 “Hello, from SimpleNestedAlternate!” 文字 MainContent 。 進行這些變更之後,新巢狀主版頁面的宣告式標記看起來應該如下所示:

<%@ Master Language="VB" MasterPageFile="~/NestedMasterPages/Simple.master" AutoEventWireup="false" CodeFile="SimpleNestedAlternate.master.vb" Inherits="NestedMasterPages_SimpleNestedAlternate" %> 
 <asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
 <asp:ContentPlaceHolder ID="head" runat="server">
 </asp:ContentPlaceHolder> </asp:Content> 
 <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" Runat="Server">
 <p>Hello, from SimpleNestedAlternate!</p> 
 <asp:ContentPlaceHolder ID="MainContent" runat="server">
 </asp:ContentPlaceHolder> 
 </asp:Content>

在資料夾中建立名為 Alternate.aspx NestedMasterPages 的內容頁面,並將它系結至 SimpleNestedAlternate.master 巢狀主版頁面。 在對應至 的內容控件中,新增 “Hello, from Alternate!” 文字。MainContent 圖 7 顯示 Alternate.aspx 透過 Visual Studio 設計工具檢視時。

Alternate.aspx系結至 SimpleNestedAlternate.master 主版頁面

圖 07Alternate.aspx 系結至 SimpleNestedAlternate.master 主版頁面 (按兩下以檢視完整大小的影像

比較圖 7 中的設計工具與圖 6 中的設計工具。 這兩個內容頁面共用最上層主版頁面 (Simple.master) 中所定義的相同版面配置,即「巢狀主版頁面教學課程(簡單)」標題。 然而,兩者在父主版頁面中都定義了不同的內容-圖 6 中的文字 “Hello, from SimpleNested!” 和圖 7 中的 “Hello, from SimpleNestedAlternate!” 文字。 授與這些差異是微不足道的,但您可以擴充此範例以包含更有意義的差異。 例如, SimpleNested.master 頁面可能包含具有其內容頁面特定選項的功能表,而 SimpleNestedAlternate.master 可能會有與其系結之內容頁面相關的資訊。

現在,假設我們需要變更整個網站配置。 例如,假設我們想要新增所有內容頁面的一般連結清單。 若要達成此目的,我們會更新最上層主版頁面 。 Simple.master 任何變更都會立即反映在其巢狀主版頁面中,並依延伸模組反映其內容頁面。

為了示範我們可以輕鬆變更整體網站配置,請開啟Simple.master主版頁面,並在和 mainContent <div> 元素之間topContent新增下列標記:

<div id="navContent"> 
 <asp:HyperLink ID="lnkDefault" runat="server" 
 NavigateUrl="~/NestedMasterPages/Default.aspx" 
 Text="Nested Master Page Example 1" /> 
 | 
 <asp:HyperLink ID="lnkAlternate" runat="server" 
 NavigateUrl="~/NestedMasterPages/Alternate.aspx" 
 Text="Nested Master Page Example 2" /> 
</div>

這會新增兩個連結至系結至 Simple.masterSimpleNested.masterSimpleNestedAlternate.master的每個頁面頂端;這些變更會立即套用至所有巢狀主版頁面及其內容頁面。 圖 8 顯示 Alternate.aspx 透過瀏覽器檢視時。 請注意頁面頂端新增連結(與圖 7 相比)。

變更為最上層主版頁面會立即反映在其巢狀主版頁面及其內容頁面中

圖 08:變更為最上層主版頁面會立即反映在其巢狀主版頁面及其內容頁面中(按兩下以檢視完整大小的影像

使用管理區段的巢狀主版頁面

此時,我們已探討巢狀主版頁面的優點,並瞭解如何在 ASP.NET 應用程式中建立和使用它們。 不過,步驟 1、2 和 3 中的範例涉及建立新的最上層主版頁面、新的巢狀主版頁面,以及新的內容頁面。 將新的巢狀主版頁面新增至具有現有最上層主版頁面和內容頁面的網站呢?

將巢狀主版頁面整合到現有的網站,並將其與現有的內容頁面建立關聯需要比從頭開始更費力。 步驟 4、5、6 和 7 會探索這些挑戰,因為我們增強我們的示範應用程式,以包含名為 AdminNested.master 的新巢狀主版頁面,其中包含系統管理員的指示,並由資料夾中的 ASP.NET 頁面 ~/Admin 使用。

將巢狀主版頁面整合到我們的示範應用程式中,引進了下列障礙:

  • 資料夾中的現有內容頁面 ~/Admin 具有主版頁面的特定預期。 對於入門版,他們預期會有特定的 ContentPlaceHolder 控件存在。 此外,~/Admin/AddProduct.aspx和 頁面會呼叫主版頁面的公用RefreshRecentProductsGrid方法、設定其 GridMessageText 屬性,或為其事件設定事件處理程式PricesDoubled~/Admin/Products.aspx。 因此,我們的巢狀主版頁面必須提供相同的 ContentPlaceHolders 和公用成員。
  • 在上一個教學課程中,我們已增強 類別, BasePage 以根據 Session 變數動態設定 Page 物件的 MasterPageFile 屬性。 如何使用巢狀主版頁面來支援動態主版頁面?

當我們建置巢狀主版頁面,並從現有的內容頁面使用它時,這兩個挑戰將會浮出水面。 我們會在發生這些問題時進行調查並加以克服。

步驟 4:建立巢狀主版頁面

我們的第一項工作是建立巢狀主版頁面,供 [系統管理] 區段中的頁面使用。 如步驟 2 中所見,新增巢狀主版頁面時,我們需要指定巢狀主版頁面的父主版頁面。 但是我們有兩個最上層主版頁面: Site.masterAlternate.master。 回想一下,我們在上一個教學課程中建立Alternate.master,並在類別中BasePage撰寫程式代碼,以在運行時間將對象的 MasterPageFile 屬性設定PageSite.masterAlternate.master ,視 Session 變數的值MyMasterPage而定。

如何設定巢狀主版頁面,使其使用適當的最上層主版頁面? 我們有兩個選項:

  • 建立兩個巢狀主版頁面和 AdminNestedSite.master AdminNestedAlternate.master,並分別將它們系結至最上層主版頁面 Site.masterAlternate.master。 在 中 BasePage,我們會將 Page 對象的 MasterPageFile 設定為適當的巢狀主版頁面。
  • 建立單一巢狀主版頁面,並讓內容頁面使用此特定主版頁面。 然後,在運行時間,我們需要在運行時間將巢狀主版頁面的 MasterPageFile 屬性設定為適當的最上層主版頁面。 (您可能已經弄清楚,主版頁面也有 MasterPageFile 屬性。

讓我們使用第二個選項。 在名為AdminNested.master~/Admin 資料夾中建立單一巢狀主版頁面檔案。 Site.master因為 和 Alternate.master 都有一組相同的 ContentPlaceHolder 控件,所以您系結至的主版頁面並不重要,儘管我鼓勵您為了一致性而系結至Site.master該主版頁面。

將巢狀主版頁面新增至 ~/Admin 資料夾。

圖 09:將巢狀主版頁面新增至 ~/Admin 資料夾。 (按兩下以檢視完整大小的影像

因為巢狀主版頁面系結至具有四個 ContentPlaceHolder 控件的主版頁面,所以 Visual Studio 會將四個內容控件新增至新的巢狀主版頁面檔案的初始標記。 就像我們在步驟 2 和 3 中所做的一樣,在每個 Content 控件中新增 ContentPlaceHolder 控件,使其與最上層主版頁面的 ContentPlaceHolder 控件同名。 此外,將下列標記新增至對應至 MainContent ContentPlaceHolder 的內容控制項:

<div class="instructions"> 
 <b>Administration Instructions:</b>
 <br /> 
 The pages in the Administration section allow you, the Administrator, to 
 add new products and view existing products. 
</div>

接下來,在 instructionsAlternateStyles.css CSS 檔案中Styles.css定義 CSS 類別。 下列 CSS 規則會導致使用類別樣式的 instructions HTML 元素以淺黃色背景色彩和黑色、實心框線顯示:

.instructions 
{
 padding: 6px; 
 border: dashed 1px black; 
 background-color: #ffb; 
 margin-bottom: 10px; 
}

由於此標記已新增至巢狀主版頁面,因此只會出現在使用這些巢狀主版頁面的頁面(也就是 [系統管理] 區段中的頁面)。

將這些新增專案新增至巢狀主版頁面之後,其宣告式標記看起來應該如下所示:

<%@ Master Language="VB" MasterPageFile="~/Site.master" AutoEventWireup="false" CodeFile="AdminNested.master.vb" Inherits="Admin_AdminNested" %> 
 <asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server"> 
 <asp:ContentPlaceHolder ID="head" runat="server"> 
 </asp:ContentPlaceHolder>
 </asp:Content> 
 <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" Runat="Server"> 
 <div class="instructions">
 <b>Administration Instructions:</b>
 <br /> 
 The pages in the Administration section allow you, the Administrator, to 
 add new products and view existing products. 
 </div>
 <asp:ContentPlaceHolder ID="MainContent" runat="server"> 
 </asp:ContentPlaceHolder>
 </asp:Content> 
 <asp:Content ID="Content3" ContentPlaceHolderID="QuickLoginUI" Runat="Server"> 
 <asp:ContentPlaceHolder ID="QuickLoginUI" runat="server"> 
 </asp:ContentPlaceHolder>
 </asp:Content> 
 <asp:Content ID="Content4" ContentPlaceHolderID="LeftColumnContent" Runat="Server"> 
 <asp:ContentPlaceHolder ID="LeftColumnContent" runat="server"> 
 </asp:ContentPlaceHolder>
 </asp:Content>

請注意,每個 Content 控件都有 ContentPlaceHolder 控件,而且 ContentPlaceHolder 控件 ID 的屬性會指派與最上層主版頁面中對應 ContentPlaceHolder 控件相同的值。 此外,[系統管理] 區段特定標記會出現在 MainContent ContentPlaceHolder 中。

圖 10 顯示 AdminNested.master 透過 Visual Studio 設計工具檢視時的巢狀主版頁面。 您可以在內容控制件頂端 MainContent 的黃色方塊中看到指示。

巢狀主版頁面會擴充最上層主版頁面,以包含系統管理員的指示。

圖 10:巢狀主版頁面會擴充最上層主版頁面,以包含系統管理員的指示。 (按兩下以檢視完整大小的影像

步驟 5:更新現有的內容頁面以使用新的巢狀主版頁面

每當我們新增內容頁面至 [系統管理] 區段時,我們需要將其系結至剛才建立的主 AdminNested.master 版頁面。 但是現有的內容頁面呢? 目前,網站中的所有內容頁面都衍生自 BasePage 類別,以程序設計方式在運行時間設定內容頁面的主版頁面。 這不是我們想要針對 [系統管理] 區段中的內容頁面的行為。 相反地,我們希望這些內容頁面一律使用 AdminNested.master 頁面。 這將是巢狀主版頁面的責任,在運行時間選擇正確的最上層內容頁面。

若要達到此所需行為的最佳方式,就是建立名為 AdminBasePage 的新自定義基頁類別,以擴充 BasePage 類別。 AdminBasePage然後可以覆寫 ,SetMasterPageFile並將 對象的 MasterPageFile 設定Page為硬式編碼值 “~/Admin/AdminNested.master”。 如此一來,任何衍生自 AdminBasePage 的頁面都會使用 AdminNested.master,而衍生自 BasePage 的任何頁面都會根據 Session 變數的值MyMasterPage,動態設定為 MasterPageFile “~/Site.master” 或 “~/Alternate.master”。

首先,將新的類別檔案新增至 App_Code 名為 AdminBasePage.vb的資料夾。 具有 AdminBasePage extend BasePage ,然後覆寫 SetMasterPageFile 方法。 在該方法中, MasterPageFile 指派值 “~/Admin/AdminNested.master”。 進行這些變更之後,您的類別檔案看起來應該如下所示:

Public Class AdminBasePage 
 Inherits BasePage 
 Protected Overrides Sub SetMasterPageFile() 
 Me.MasterPageFile = "~/Admin/AdminNested.master" 
 End Sub 
End Class

我們現在必須在 [系統管理] 區段中有現有的內容頁面衍生自 AdminBasePage ,而不是 BasePage。 移至資料夾中每個內容頁面 ~/Admin 的程式代碼後置類別檔案,並進行這項變更。 例如,在 ~/Admin/Default.aspx 中,您會從下列專案變更程式碼後置類別宣告:

Partial Class Admin_Default 
 Inherits BasePage

變更為:

Partial Class Admin_Default 
 Inherits AdminBasePage

圖 11 描述最上層主版頁面(或Alternate.master)、巢狀主版頁面 (Site.masterAdminNested.master), 以及 [系統管理] 區段內容頁面彼此的關聯性。

巢狀主版頁面定義管理區段中頁面的特定內容

圖 11:巢狀主版頁面定義系統管理區段中頁面的特定內容(按兩下以檢視完整大小的影像

步驟 6:鏡像主版頁面的公用方法和屬性

回想一下, ~/Admin/AddProduct.aspx~/Admin/Products.aspx 頁面會以程序設計方式與主版頁面互動: ~/Admin/AddProduct.aspx 呼叫主版頁面的公用 RefreshRecentProductsGrid 方法並設定其 GridMessageText 屬性; ~/Admin/Products.aspx 具有 事件的事件處理程式 PricesDoubled 。 在上述教學課程中,我們建立了定義MustInheritBaseMasterPage這些公用成員的類別。

~/Admin/AddProduct.aspx~/Admin/Products.aspx 頁面假設其主版頁面衍生自 BaseMasterPage 類別。 不過,頁面 AdminNested.master 目前會擴充 類別 System.Web.UI.MasterPage 。 因此,造訪 ~/Admin/Products.aspx InvalidCastException 時會擲回訊息:「無法將類型為 『ASP.admin_adminnested_master』 的物件轉換成類型 『BaseMasterPage』」。

若要修正此問題,我們必須讓程式 AdminNested.master 代碼後置類別擴充 BaseMasterPage。 從下列來源更新巢狀主版頁面的程式代碼後置類別宣告:

Partial Class Admin_AdminNested 
 Inherits System.Web.UI.MasterPage

變更為:

Partial Class Admin_AdminNested 
 Inherits BaseMasterPage

我們還沒有完成。 我們需要覆寫標示為 MustOverride的成員,也就是 RefreshRecentProductsGridGridMessageText。 最上層主版頁面會使用這些成員來更新其使用者介面。 (實際上,只有 Site.master 主版頁面會使用這些方法,雖然兩個最上層主版頁面都實作這些方法,因為兩者都是擴充 BaseMasterPage的 。

雖然我們需要在 中 AdminNested.master實作這些成員,但這些實作只需要在巢狀主版頁面所使用的最上層主版頁面中呼叫相同的成員。 例如,當 [系統管理] 區段中的內容頁面呼叫巢狀主版頁面 RefreshRecentProductsGrid 的 方法時,所有巢狀主版頁面都必須接著呼叫 Site.masterAlternate.masterRefreshRecentProductsGrid 方法。

若要達成此目的,請先將下列 @MasterType 指示詞新增至 頂端 AdminNested.master

<%@ MasterType TypeName="BaseMasterPage" %>

回想一下,指示詞會將 @MasterType 強型別屬性新增至名為 Master的程序代碼後置類別。 然後覆寫 RefreshRecentProductsGridGridMessageText 成員,並直接將呼叫委派給 Master的對應方法:

Partial Class Admin_AdminNested 
 Inherits BaseMasterPage 
 Public Overrides Property GridMessageText() As String 
 Get 
 Return Master.GridMessageText 
 End Get 
 Set(ByVal value As String) 
 Master.GridMessageText = value 
 End Set 
 End Property 
 Public Overrides Sub RefreshRecentProductsGrid()
 Master.RefreshRecentProductsGrid()
 End Sub 
End Class

有了此程式代碼,您應該能夠流覽並使用 [系統管理] 區段中的內容頁面。 圖 12 顯示 ~/Admin/Products.aspx 透過瀏覽器檢視的頁面。 如您所見,頁面包含 [系統管理指示] 方塊,其定義於巢狀主版頁面中。

管理區段中的內容頁面包含每個頁面頂端的指示

圖 12:管理區段中的內容頁面包含每個頁面頂端的指示(按兩下以檢視完整大小的影像

步驟 7:在運行時間使用適當的最上層主版頁面

雖然 [系統管理] 區段中的所有內容頁面都完全正常運作,但它們都使用相同的最上層主版頁面,並忽略使用者在 上 ChooseMasterPage.aspx選取的主版頁面。 此行為是因為巢狀主版頁面在其 指示詞中<%@ Master %>以靜態方式將 屬性MasterPageFile設定為 Site.master

若要使用用戶選取的最上層主版頁面,我們需要將 的 MasterPageFile 屬性設定AdminNested.master為 Session 變數中的MyMasterPage值。 因為我們在 中BasePage設定內容頁面MasterPageFile的屬性,您可能會認為我們會在 或AdminNested.master的程式代碼後置類別中BaseMasterPage設定巢狀主版頁面MasterPageFile的屬性。 不過,這無法運作,因為我們必須在 PreInit 階段結束時設定 MasterPageFile 屬性。 我們可以從主版頁面以程序設計方式點選頁面生命週期的最早時間是 Init 階段(在 PreInit 階段之後發生)。

因此,我們需要從內容頁面設定巢狀主版頁面 MasterPageFile 的 屬性。 唯一 AdminNested.master 使用主版頁面的內容頁面衍生自 AdminBasePage。 因此,我們可以將這個邏輯放在該處。 在步驟 5 中,我們將 SetMasterPageFile Page 對象的 MasterPageFile 屬性設定為 “~/Admin/AdminNested.master”。 更新 SetMasterPageFile 為也會將主版頁面的 MasterPageFile 屬性設定為儲存在工作階段中的結果:

Public Class AdminBasePage 
 Inherits BasePage 
 Protected Overrides Sub SetMasterPageFile() 
 Me.MasterPageFile = "~/Admin/AdminNested.master" 
 Page.Master.MasterPageFile = MyBase.GetMasterPageFileFromSession() 
 End Sub 
End Class

我們在 GetMasterPageFileFromSession 上一個教學課程中新增至 BasePage 類別的方法會根據 Session 變數值傳回適當的主版頁面檔案路徑。

有了這項變更,使用者的主版頁面選取範圍會延續至 [系統管理] 區段。 圖 13 顯示與圖 12 相同的頁面,但在使用者將主版頁面選取專案變更為 Alternate.master之後。

巢狀管理頁面使用用戶選取的最上層主版頁面

圖 13:巢狀管理頁面使用使用者選取的最上層主版頁面(按兩下以檢視完整大小的影像

摘要

就像內容頁面可以系結至主版頁面一樣,讓子主版頁面系結至父主版頁面,即可建立巢狀主版頁面。 子主版頁面可以定義其父系 ContentPlaceHolders 的內容控件;然後,它可以將自己的 ContentPlaceHolder 控件(以及其他標記)新增至這些內容控件。 巢狀主版頁面在大型 Web 應用程式中相當實用,其中所有頁面共用整體外觀和風格,但網站的某些區段需要唯一的自定義。

快樂的程序設計!

深入閱讀

如需本教學課程中所討論主題的詳細資訊,請參閱下列資源:

關於作者

斯科特·米切爾,多個 ASP/ASP.NET 書籍的作者,4GuysFromRolla.com 的創始人,自1998年以來一直與Microsoft Web 技術合作。 斯科特擔任獨立顧問、教練和作家。 他的最新書是 山姆斯在24小時內 ASP.NET 3.5。 斯科特可以透過 mitchell@4GuysFromRolla.com 他在的部落格聯繫到或通過他的博客 http://ScottOnWriting.NET

特別感謝

本教學課程系列已由許多實用的檢閱者檢閱。 有興趣檢閱我即將推出的 MSDN 文章嗎? 如果是,請將一行放在 mitchell@4GuysFromRolla.com