共用方式為


巢狀主版頁面 (VB)

作者 :Scott Mitchell

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

簡介

在過去九個教學課程中,我們已瞭解如何使用主版頁面實作全網站版面配置。 簡單地說,主版頁面可讓我們頁面開發人員在主版頁面中定義通用標記,以及可在內容頁面逐頁自定義的特定區域。 主版頁面中的 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:建立簡單 Top-Level 主版頁面

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

建立名為 NestedMasterPages 的新資料夾,然後將新的主版頁面檔案新增至名為 Simple.master的資料夾。 (請參閱圖 1,以取得新增此資料夾和檔案之後 方案總管 的螢幕快照。) 將AlternateStyles.css樣式表單檔案從 方案總管 拖曳到 Designer。 這會將 元素新增 <link> 至 元素中的 <head> 樣式表單檔案,之後主版頁面的 <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 Form 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 Designer 時的主版頁面。

載入 Visual Studio Designer 時的簡單點主版主版頁面。

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

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

Simple.master 包含兩個 ContentPlaceHolder 控件: MainContent 我們在 Web Form 內新增的 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 控制項所參考的名稱。 也就是說,將名為 MainContent 的 ContentPlaceHolder 控件新增至 中SimpleNested.masterMainContent參考 ContentPlaceHolder 的 Simple.masterContentPlaceHolder 控件。 在參考 head ContentPlaceHolder 的內容控制件中執行相同動作。

注意

雖然建議在巢狀主版頁面中命名 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 新增至內容控件。

Top-Level 和巢狀主版頁面指定內容頁面的版面配置

圖 05:Top-Level 和巢狀主版頁面指定內容頁面的配置 (按兩下即可檢視大小完整的影像)

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

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

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

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

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

<%@ 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.aspxNestedMasterPages 的內容頁面,並將它系結至 SimpleNestedAlternate.master 巢狀主版頁面。 在對應至 MainContent的內容控件中新增文字 “Hello, from Alternate!” 文字。 圖 7 顯示Alternate.aspx透過 Visual Studio Designer 檢視時。

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

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

將圖 7 中的 Designer 與圖 6 中的 Designer 進行比較。 這兩個內容頁面共用最上層主版頁面中所定義的相同版面配置, 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>

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

變更為 Top-Level 主版頁面會立即反映在其巢狀主版頁面及其內容頁面中

圖 08:變更為 Top-Level 主版頁面會立即反映在其巢狀主版頁面及其內容頁面中, (按兩下即可檢視完整大小的影像)

使用 [系統管理] 區段的巢狀主版頁面

此時,我們已查看巢狀主版頁面的優點,並瞭解如何在 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.masterAdminNestedAlternate.master,並分別將它們系結至最上層主版頁面 Site.masterAlternate.master。 在 BasePage中,我們會將 Page 對象的 MasterPageFile 設定為適當的巢狀主版頁面。
  • 建立單一巢狀主版頁面,並讓內容頁面使用此特定主版頁面。 然後,在運行時間,我們需要在運行時間將巢狀主版頁面 MasterPageFile 的 屬性設定為適當的最上層主版頁面。 (您可能現在已瞭解,主版頁面也有 MasterPageFile property.)

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

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

圖 09:將巢狀主版頁面新增至 ~/Admin 資料夾。 (按鍵即可檢視完整大小的映像)

由於巢狀主版頁面系結至具有四個 ContentPlaceHolder 控件的主版頁面,因此 Visual Studio 會將四個內容控件新增至新的巢狀主版頁面檔案的初始標記。 如同我們在步驟 2 和 3 中所做的一樣,請在每個內容控件中新增 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>

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

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

巢狀主版頁面會擴充 Top-Level 主版頁面,以包含系統管理員的指示。

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

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

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

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

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

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

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

Partial Class Admin_Default 
 Inherits BasePage

變更為:

Partial Class Admin_Default 
 Inherits AdminBasePage

圖 11 描述最上層主版頁面如何 (Site.masterAlternate.master) 、巢狀主版頁面 (AdminNested.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.aspxInvalidCastException 時會擲回訊息:「無法將類型 』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的程序代碼後置類別。 然後覆寫 和 GridMessageText 成員,RefreshRecentProductsGrid並直接委派對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:在運行時間使用適當的 Top-Level 主版頁面

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

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

因此,我們需要從內容頁面設定巢狀主版頁面的 MasterPageFile 屬性。 唯一 AdminNested.master 使用主版頁面的內容頁面衍生自 AdminBasePage。 因此,我們可以將這個邏輯放在該處。 在步驟 5 中,我們將 SetMasterPageFile Page 對象的 MasterPageFile 屬性設定為 “~/管理員/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之後。

巢狀管理頁面會使用用戶選取 Top-Level 主版頁面

圖 13:巢狀管理頁面會使用使用者所選取 Top-Level 主版頁面, (按兩下即可檢視全大小的影像)

摘要

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

快樂的程序設計!

深入閱讀

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

關於作者

Scott Mitchell 是多個 ASP/ASP.NET 書籍的作者,以及 4GuysFromRolla.com 的建立者,自 1998 年起就與 Microsoft Web 技術合作。 Scott 是獨立的顧問、訓練者和作者。 他的最新書籍是 Sams 在 24 小時內自行 ASP.NET 3.5。 Scott 可以透過 mitchell@4GuysFromRolla.com 在 上的部落格或透過 http://ScottOnWriting.NET其部落格來連線。

特別感謝

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