巢狀主版頁面 (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.master
或 Alternate.master
,視使用者的選取專案而定)。
注意
目前,假設網站只有一個主版頁面。 Site.master
在本教學課程稍後,我們將說明使用巢狀主版頁面搭配兩個(或更多)主版頁面,從「使用管理區段的巢狀主版頁面」開始。
假設我們被要求自定義 [系統管理] 頁面的版面配置,以包含其他資訊或鏈接,否則不會出現在網站中的其他頁面中。 實作這項需求有四種技術:
- 手動新增系統管理特定資訊,並連結至資料夾中的每個內容頁面
~/Admin
。 Site.master
更新主版頁面以包含 [系統管理] 區段特定資訊和鏈接,然後將程式代碼新增至主版頁面,根據其中一個系統管理頁面是否瀏覽,顯示或隱藏這些區段。- 為 [系統管理] 區段建立新的主版頁面、從 複製標記
Site.master
、新增 [系統管理] 區段特定資訊和鏈接,然後更新資料夾中的內容頁面~/Admin
,以使用這個新的主版頁面。 - 建立巢狀主版頁面,系結至
Site.master
資料夾中的內容頁面~/Admin
,並使用這個新的巢狀主版頁面。 這個巢狀主版頁面只會包含系統管理頁面特有的其他資訊和連結,而且不需要重複中Site.master
已定義的標記。
第一個選項是最不討人看得起的。 使用主版頁面的整個點,就是不需手動複製並貼上通用標記至新的 ASP.NET 頁面。 第二個選項是可接受的,但讓應用程式更容易維護,因為它會大量顯示只有偶爾顯示的標記的主版頁面,而且需要開發人員編輯主版頁面來處理此標記,而且必須記住何時、確切地顯示特定標記,而不是隱藏時。 此方法較不可行,因為這個單一主版頁面需要容納更多類型的網頁自定義。
第三個選項會移除第二個選項所呈現的雜亂和複雜度問題。 不過,選項三的主要缺點是,它要求我們複製並貼上通用版面配置,並 Site.master
貼到新的 [系統管理] 區段特定主版頁面。 如果我們稍後決定變更全網站版面配置,我們必須記得在兩個地方變更它。
第四個選項,巢狀主版頁面,給我們最好的第二和第三個選項。 全網站版面配置資訊會保留在一個檔案中,也就是最上層主版頁面,而特定區域的特定內容則會分成不同的檔案。
本教學課程從建立和使用簡單的巢狀主版頁面開始。 我們會建立全新的頂層主版頁面、兩個巢狀主版頁面和兩個內容頁面。 從「使用「管理區段的巢狀主版頁面」開始,我們探討如何更新現有的主版頁面架構,以包含使用巢狀主版頁面。 具體而言,我們會建立巢狀主版頁面,並用它來包含資料夾中內容頁面 ~/Admin
的其他自定義內容。
步驟 1:建立簡單的最上層主版頁面
根據其中一個現有的主版頁面建立巢狀主圖形,然後更新現有的內容頁面以使用這個新的巢狀主版頁面,而不是最上層主版頁面需要一些複雜度,因為現有的內容頁面已經預期最上層主版頁面中定義的特定 ContentPlaceHolder 控件。 因此,巢狀主版頁面也必須包含具有相同名稱的相同 ContentPlaceHolder 控件。 此外,我們的特定示範應用程式有兩個主版頁面(Site.master
和 Alternate.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 設計工具中載入時的主版頁面。
圖 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:核取 [選取主版頁面] 複選框以新增巢狀主版頁面(按兩下以檢視完整大小的影像)
圖 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.master
MainContent
參考 ContentPlaceHolder 的 Simple.master
ContentPlaceHolder 控件。 在參考 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.master
、 SimpleNested.master
和 Default.aspx
- 以及它們彼此的關聯性。 如圖所示,巢狀主版頁面會為其父系的 ContentPlaceHolder 實作 Content 控件。 如果這些區域必須可供內容頁面存取,巢狀主版頁面必須將自己的 ContentPlaceHolders 新增至 Content 控制件。
圖 05:最上層和巢狀主版頁面指定內容頁面的版面配置(按兩下以檢視完整大小的影像)
此行為說明內容頁面或主版頁面如何只辨識其父主版頁面。 Visual Studio 設計工具也會指出此行為。 圖 6 顯示 的設計工具 Default.aspx
。 雖然設計工具清楚顯示哪些區域可從內容頁面編輯,哪些部分不是,但不會釐清巢狀主版頁面有哪些不可編輯的區域,以及哪些區域來自最上層主版頁面。
圖 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 設計工具檢視時。
圖 07: Alternate.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.master
、 SimpleNested.master
或 SimpleNestedAlternate.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.master
和 Alternate.master
。 回想一下,我們在上一個教學課程中建立Alternate.master
,並在類別中BasePage
撰寫程式代碼,以在運行時間將對象的 MasterPageFile
屬性設定Page
為 Site.master
或 Alternate.master
,視 Session 變數的值MyMasterPage
而定。
如何設定巢狀主版頁面,使其使用適當的最上層主版頁面? 我們有兩個選項:
- 建立兩個巢狀主版頁面和
AdminNestedSite.master
AdminNestedAlternate.master
,並分別將它們系結至最上層主版頁面Site.master
和Alternate.master
。 在 中BasePage
,我們會將Page
對象的MasterPageFile
設定為適當的巢狀主版頁面。 - 建立單一巢狀主版頁面,並讓內容頁面使用此特定主版頁面。 然後,在運行時間,我們需要在運行時間將巢狀主版頁面的
MasterPageFile
屬性設定為適當的最上層主版頁面。 (您可能已經弄清楚,主版頁面也有MasterPageFile
屬性。
讓我們使用第二個選項。 在名為AdminNested.master
的 ~/Admin
資料夾中建立單一巢狀主版頁面檔案。 Site.master
因為 和 Alternate.master
都有一組相同的 ContentPlaceHolder 控件,所以您系結至的主版頁面並不重要,儘管我鼓勵您為了一致性而系結至Site.master
該主版頁面。
圖 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>
接下來,在 instructions
和 AlternateStyles.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.master
AdminNested.master
), 以及 [系統管理] 區段內容頁面彼此的關聯性。
圖 11:巢狀主版頁面定義系統管理區段中頁面的特定內容(按兩下以檢視完整大小的影像)
步驟 6:鏡像主版頁面的公用方法和屬性
回想一下, ~/Admin/AddProduct.aspx
和 ~/Admin/Products.aspx
頁面會以程序設計方式與主版頁面互動: ~/Admin/AddProduct.aspx
呼叫主版頁面的公用 RefreshRecentProductsGrid
方法並設定其 GridMessageText
屬性; ~/Admin/Products.aspx
具有 事件的事件處理程式 PricesDoubled
。 在上述教學課程中,我們建立了定義MustInherit
BaseMasterPage
這些公用成員的類別。
~/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
的成員,也就是 RefreshRecentProductsGrid
和 GridMessageText
。 最上層主版頁面會使用這些成員來更新其使用者介面。 (實際上,只有 Site.master
主版頁面會使用這些方法,雖然兩個最上層主版頁面都實作這些方法,因為兩者都是擴充 BaseMasterPage
的 。
雖然我們需要在 中 AdminNested.master
實作這些成員,但這些實作只需要在巢狀主版頁面所使用的最上層主版頁面中呼叫相同的成員。 例如,當 [系統管理] 區段中的內容頁面呼叫巢狀主版頁面 RefreshRecentProductsGrid
的 方法時,所有巢狀主版頁面都必須接著呼叫 Site.master
或 Alternate.master
的 RefreshRecentProductsGrid
方法。
若要達成此目的,請先將下列 @MasterType
指示詞新增至 頂端 AdminNested.master
:
<%@ MasterType TypeName="BaseMasterPage" %>
回想一下,指示詞會將 @MasterType
強型別屬性新增至名為 Master
的程序代碼後置類別。 然後覆寫 RefreshRecentProductsGrid
和 GridMessageText
成員,並直接將呼叫委派給 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 技術合作。 Scott 擔任獨立顧問、講師和作家。 他的最新書是 山姆斯在24小時內 ASP.NET 3.5。 斯科特可以透過 mitchell@4GuysFromRolla.com 他在的部落格聯繫到或通過他的博客 http://ScottOnWriting.NET。
特別感謝
本教學課程系列已經過許多熱心的檢閱者檢閱。 有興趣檢閱我即將推出的 MSDN 文章嗎? 如果是,請將一行放在 mitchell@4GuysFromRolla.com