国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > 綜合 > 正文

通過可視化繼承和頁面模板控制站點設計

2024-07-21 02:16:07
字體:
來源:轉載
供稿:網友

作者:fritz onion
相關技術:模板、asp.net,master pages
難度:★★★☆☆
讀者類型:asp.net開發人員

    [導讀]本文首先介紹了在傳統的下“模板”的實現,包括了asp和asp.net 1.x的實現,然后介紹了asp.net 2.0下模板的實現方式——master pages,最后闡述了母版頁的實現原理。

    多年以來,人員一直在努力通過多種技術來“模板化”他們的站點,但沒有任何一種經證明技術,能夠在整個站點中維護標準化外觀的真正通用,且可重用的方法。母版頁作為在asp.net 2.0中問世的最令人期待的功能之一,最終提供了一種在應用程序中基于模板設計頁面公認、一流的方法。
模板設計
    在web站點設計中為所有頁面定義一種標準的外觀是令人賞心悅目的。這可能包括公用頁眉、頁腳和菜單,他能夠在整個站點中提供一組核心功能和外觀。對于通過如asp或asp.net這樣的技術生成的動態站點而言,如果將所有頁面上的這些公用功能整合為某種類型的頁面模板將十分有用,這可以使各個頁面只包含它自己的獨特內容,并且提供一個在外觀和行為方面進行站點范圍更改的中心位置。有關可以從某種類型的頁面模板技術中受益的站點的簡單而具體的示例,請參見圖1。


圖1 簡單的模板化站點

    該特定頁面在頂部有一個頁眉,在底部有一個頁腳,在左側有一個導航欄,并且有一個填滿了其余空間的用于頁面特有內容的區域。理想情況下,頁眉、頁腳和導航欄應該只需要定義一次,并且以某種方式應用到該站點中的所有頁面。

    這正好是asp.net 2.0中的母版頁能夠簡單而巧妙地解決的問題。通過定義一個母版頁,并且隨后根據它來創建許多內容頁,您可以非常容易地用單個模板(母版頁)所驅動的通用外觀來創建站點。但是,在我探討母版頁的細節之前,了解一下目前開發人員如何在asp和asp.net 1.x中生成模板化站點將是有用的。
在傳統asp中生成模板
    利用asp 3.0生成的許多站點都使用了模板的概念——一般是使用服務器端include (ssi)指令。ssi指令提供了在asp頁面內特定位置插入文件內容的能力。一種通用技術是使用ssi指令來引入常用的元素,如頁腳、頁眉和導航欄。圖2演示了這種做法。


圖2 asp中的服務器端包含指令

    盡管該技術在正確方向上邁出了一步,但它仍然意味著每個頁面除了生成所有特定于頁面的內容以外,還必須生成周圍的布局元素和總體結構。許多站點采用的另一種更加具有模板特征的方法是:指定兩個通用的包含文件(如pagestart.asp和pageend.asp),并且使這兩個文件不僅包含通用的導航欄、頁眉和頁腳,還包含周圍的布局元素和總體頁面結構。留待各個頁面添加的所有元素是它特有的內容。

    該方法在整個站點的集中式模板中提供了許多開發人員需要的控制;但它也有幾個缺點。首先,不支持用于編輯含有ssi指令的文件的設計器,因此設計人員必須實現合并的呈現效果以查看完整的頁面外觀,只是稍后需要將其重新分開。其次,包含機制過分簡單,因為它只是在asp分析程序進行服務器端計算之前將一個文件的內容插入到另一個文件中。這意味著在匹配html元素結束標記以及正確選擇包含位置以避免錯誤呈現時,很容易出錯。同時,很難自定義被包含文件的某些部分。在可以從msdn magazine web站點下載的asp“technique2”示例中,您立即就可以注意到的一個缺陷是每個頁面的標題都被有意保留為空。發生這種情況的原因在于:標題僅在頂級page_start包含文件中指定一次,并且沒有什么巧妙的方法來讓包含模板的頁面指定應該在標題元素中出現的內容。最后,使用包含文件需要系統開銷,因為它們增加了asp腳本引擎緩存的總大小。

    基于上述使用服務器端包含指令的簡單方法,真正通用的模板化機制在理想情況下應該具有下列五個功能:
具有某種功能,使開發人員能夠創建可以獨立定義、并且可以在多個頁面中重用的頁面部分 能夠為頁面定義可供其他頁面用作模板的“外殼” 頁面能夠改變繼承的模板頁面內部各種元素,例如更改標題元素 能夠在頁面內部以聲明方式指定備用頁面模板 能夠使用與頁面關聯的模板實際查看該頁面的呈現版本
    將服務器端包含文件用于asp 3.0可以滿足上述第一個條件,并且可以在某種程度上滿足第二個條件,但無法提供最后三個功能。
在asp.net 1.x中生成模板化站點
    asp.net引入了一種全新的、基于對象的編程模型,從而有可能提供一種更新穎、更優雅的模板化機制。asp.net通過要呈現到客戶端元素的完整層次化對象模型,向您提供了每個頁面的服務器端表示形式,而不必依賴于asp 3.0中比較低級的ssi機制。最恰當地反映ssi文件功能的功能是用戶控件。用戶控件提供了一種聲明性方式,以便創建可以將其內容和行為插入其他頁面任意位置的自定義控件,因此使用這些控件作為定義頁面的可重用部分的通用方法是非常簡單的,如圖3所示。


圖3 帶有用戶控件的可重用頁面部分

    除了充當簡單內容占位符以外,用戶控件還是能夠公開屬性、方法和事件功能的完整控件。與服務器端包含指令不同,您可以賦予用戶控件能夠影響其在頁面上呈現的功能。例如,您可以在名為showbreadcrumbs的頁眉控件上創建一個屬性,以便能夠根據需要選擇性地打開或關閉面包屑功能。

    但是,用戶控件重用模型有一些局限和缺點。首先,許多開發人員發現,必須在將使用用戶控件的每個頁面中針對每個用戶控件添加一條register指令,因此非常麻煩。具有諷刺意味的是,許多asp.net開發人員已經轉而使用ssi指令將register指令集合導入他們的所有頁面中,以便只用一條ssi指令替換多個代碼行。然而,更為重要的是,沒有任何一種內置方式可以使用用戶控件來滿足我在前面列出的有關開發模板化機制的五個條件中的任何一個(第一個條件除外,因為您可以創建可重用的頁面部分)。

    asp.net確實提供了一種更為豐富的對象模型,并且許多人已經建立了他們自己的模板化機制,以克服asp.net 1.x中缺少原生模板化機制的缺點。借助于一點兒創造性和一些聰明的編碼,您可以生成通用的模板化機制。大多數實現都依賴于以下事實:您有機會在page類為您自動構建的控件層次結構被發送回客戶端之前操縱該控件層次結構。例如,一種技術是創建一個通用的、派生于page的基類(該基類能夠提取所生成的頁面層次結構中的控件),動態加載充當頁面模板的用戶控件,然后將提取到的控件插入用戶控件層次結構中的已知位置。該技術的完整實現包含在本文的代碼下載資料中。

    使用與此類似的技術,可以非常接近于達到真正有用的模板化機制所需要的全部五個條件。具有用于定義可重用頁面部分的用戶控件。具有一種頁面模板機制,通過該機制,可以定義單個模板并將其應用于系統中任意數量的頁面。使用該技術可以定義模板中的“可替換”元素,并且可以為每個頁面指定備用模板。所缺少的一個功能就是設計器集成—如果沒有visual studio .net在識別這一模板化技術方面提供幫助,則要實現該功能確實是不可能的。
與此類似的自定義模板技術的另一個缺點是:沒有一種完成這一工作的受到認可的方法,并且.net framework中沒有支持這一技術的內置組件。這意味著每個站點所使用的模板化機制都可能完全不同。

    盡管asp.net為您提供了極其靈活且更為強大的編程模型,但它仍然不具有用于模板化站點的內置機制。特別是,盡管某些開發人員已經通過巧妙地使用控件層次結構替換和用戶控件生成了模板化機制,但他們仍需要完成額外的配置步驟,并且更為重要的是,他們不具有設計器支持。這時候,讓我們走入asp.net 2.0中的母版頁
母版頁
    asp.net 2.0中母版頁的問世代表著microsoft提供了第一個能夠滿足我在前面概述的全部條件的模板化機制。他們提供了站點級別的頁面模板、一種用于進行細粒度內容替換的機制、對頁面應該使用哪個模板的編程控制和聲明性控制,或許最引人注目的是,他們提供了集成的設計器支持。從技術角度來說,母版頁的實現方式與我所描述的asp.net 1.1中自定義模板機制的實現方式非常類似,但增加了來自visual studio 2005的設計器支持,并且它現在是受到認可和支持的通過可視化繼承來構建模板化站點的方式,這一切使您最終擁有了一種完整的模板解決方案。
asp.net 2.0中母版頁的實現包含兩個概念元素:母版頁和內容頁。母版頁充當內容頁的模板,而內容頁則提供內容以填充母版頁中要求“填滿”的部分。母版頁在本質上是一個標準的asp.net頁面,不同之處在于它使用擴展名.master以及指令(而不是使用)。該母版頁文件充當其他頁面的模板,因此通常它將包含頂級html元素、主窗體、頁眉、頁腳等等。在母版頁內,您可以在希望內容頁提供特定于頁面的內容的位置上添加contentplaceholder控件的實例,如圖4 所示。

<!-- file: sitetemplate.master -->
<%@ master language="c#" %>

<html>
<head>
    <title>
        <asp:contentplaceholder runat="server" id="_titlecontent">
            standard title
        </asp:contentplaceholder>
    </title>
</head>
<body>
    <form runat="server">
        <h2>common header</h2>

        <asp:contentplaceholder runat="server" id="_maincontent" />

        <h2>common footer</h2>
    </form>
</body>
</html>

圖4 添加占位符實例

    相反,內容頁只是使用masterpagefile屬性在其頁面指令中指定關聯母版頁的普通.aspx文件。這些頁面必須僅包含content控件的實例,因為它們的唯一用途就是為所繼承的母版頁模板提供內容。每個content控件都必須映射到在所引用的母版頁中定義的特定contentplaceholder控件(該控件的內容將在呈現時插入到母版頁的占位符中)。下面的內容頁為圖4 中所示的sitetemplate.master母版頁提供內容:

<!-- file: default.aspx -->
<%@ page language="c#" masterpagefile="sitetemplate.master" %>

<asp:content contentplaceholderid="_titlecontent" runat="server">
    main page
</asp:content>
<asp:content contentplaceholderid="_maincontent" runat="server">
    this is the content for the default page.
</asp:content>

    請注意,通過該機制,您可以指定要放置在母版頁模板中非常具體的位置上的內容。剛剛顯示的示例說明了如何通過在母版頁的標題元素內提供一個contentplaceholder控件,以及在內容頁中提供一個具有匹配contentplaceholderid的相應content控件,來輕松地解決用模板生成唯一頁面標題的微妙問題。該示例還闡明了母版頁如何為占位符提供默認內容,因此如果內容頁決定不為特定的占位符提供content控件,則它將具有默認的呈現效果。


圖5 在 asp.net 中使用母版頁來呈現頁

    在母版頁的基本結構就緒之后,現在我可以重新考察我在前面使用其他技術生成的模板化示例。請回想一下,該示例使用可重用的頁面內容元素(asp.net中的用戶控件)來定義頁眉、導航欄和頁腳。模板頁使用這些元素來布置頁面,而內容頁則為頁面提供內部內容。圖5 使用母版頁和內容頁顯示了該示例的呈現效果。


圖6 針對母版頁的設計支持

    更為引人注目的事實是母版頁可以被visual studio 2005中的設計器所支持,因此當您以可視方式編輯內容頁時,它將以灰色顯示所繼承的母版頁的內容,從而使您對頁面的最終呈現效果一目了然。圖6顯示了使用母版頁的延續示例在編輯隸屬于我的母版頁的內容頁時所具有的外觀。
實現細節
    正如前面所提到的那樣,母版頁和內容頁的實現方式與許多開發人員在asp.net 1.x中生成他們自己的自定義模板化機制時所采用的方法非常類似。特別是,masterpage類派生于usercontrol,因此繼承了用戶控件所提供的相同的通用容器功能。與我在前面所討論的自定義實現極為類似,母版頁所定義的模板被插入到為請求的頁面所生成的控件層次結構中。這一插入操作剛好發生在page類的init事件之前,以便所有控件都可以在init(此時通常會對控件執行編程操縱)之前準備就緒。

    對母版頁的控件層次結構和頁面的控件層次結構執行實際合并的方式與我在前面概述的方法類似。母版頁的頂級控件(該控件將與包含該母版頁的文件具有相同的名稱)將作為根控件插入到新的頁面層次結構中。然后,將頁面中每個content控件的內容作為子控件集合插入到相應的contentplaceholder控件的下方。圖7 顯示了一個具有關聯母版頁的示例內容頁,以及所得到的合并控件層次結構(它是在頁面處理過程中于init事件之前創建的)。請注意用不同顏色標記的從屬關系,它們表明了所得到的層次結構中每個控件的來歷。


圖7 母版頁和內容頁的混合層次

    該實現的含意之一是:母版頁本身只是頁面類層次結構中的另一個控件,并且您可以直接對母版頁執行您習慣于對控件執行的任何任務。與任何給定頁面相關聯的當前母版頁始終可以通過master屬性訪問器使用。作為與母版頁交互的示例,您可以在圖7 中所示的default.aspx頁面內部添加代碼,以便用編程方式訪問由母版頁隱式添加的htmlform,如下面的代碼片段所示:

void page_load(object sender, eventargs e)
{
    htmlform f = (htmlform)master.findcontrol("_theform");
    if (f != null)
    {
        // use f here...
    }
}

    除了訪問母版頁以外,您還可以在運行時更改內容頁的母版頁從屬關系。masterpagefile屬性作為page類上的公共屬性公開,并且可以在任何頁面的代碼內部進行修改。對該屬性的任何修改都必須在page類的新preinit事件的處理程序中進行才能生效,因為母版頁的創建以及與母版頁的合并都會在激發init事件之前發生。可以將下面的onpreinit方法重寫添加到任何使用母版頁的page類,以便用編程方式更改母版頁從屬關系:

protected override void onpreinit(eventargs e)
{
    this.masterpagefile = "othertemplate.master";
    base.onpreinit(e);
}
詳細用法
    當您開始在站點設計中使用母版頁時,如果您從未使用過站點級別模板化機制,則可能會遇到一些以前沒有發生過的問題。第一個問題與所引用資源(如圖像或樣式表)中的相對路徑有關。當您創建母版頁時,請務必記住:在計算相對路徑時作為起始位置的目錄很可能會基于所訪問的頁面而改變。請考慮一下圖8中所示的站點的目錄結構。


圖8 站點目錄結構

    如果您要從masterpages目錄的site.master中添加對images目錄中check.gif圖像的引用,則可能會傾向于添加一個簡單的圖像元素,如下所示:

<pre class="clscode">
<img src="http://www.163design.net/n/images/check.gif" />

    遺憾的是,只有當頁面所在的相對目錄位置類似于作為母版頁的圖像所在的位置時(如page1.aspx),這種方法才有效。任何其他頁面(如default.aspx)都無法正確解析相對路徑。該問題的一種解決方案是使用asp.net中的根路徑引用語法,并且確保從服務器端控件(這是該語法能夠生效的唯一位置)進行所有相對引用。我在前面提到的圖像引用將變為:

<img src="http://www.163design.net/n/images/check.gif" />

    另一種選擇是依賴以下事實:服務器端控件中的相對路徑引用是相對于它們被放置到的母版頁進行計算的。這意味著可以將圖像引用更改為以下形式:

<img src="http://www.163design.net/n/a/~/images/check.gif" runat="server" />

    引用母版頁的頁面中的服務器端路徑引用仍然相對于頁面本身,因此您不必更改可能已經就緒的任何技術來處理頁面中的相對引用。

    asp.net開發人員在第一次遇到母版頁時提出的另一個常見請求是:他們希望能夠要求應用程序中的所有頁面都是引用特定母版頁的內容頁。盡管不存在這種“必用”屬性,但您可以通過向web.config文件中添加一個pages元素以指定一個通用的母版頁,來指定一個在默認情況下用于應用程序所有頁面的母版頁,如下面的代碼片段所示:

<!-- file: web.config -->
<configuration>
    <pages masterpagefile="~/sitetemplate.master" />
</configuration>

    像在應用程序級別指定的任何設置一樣,單個頁面可以選擇重寫默認的masterpagefile屬性,但如果將該語句添加到您的配置文件中,則可以保證不會意外地將任何不具有關聯母版頁的頁面添加到您的應用程序中。

    最后,您可能會發現擁有“元”母版頁(即一組母版頁的母版頁)會很有用。母版頁支持任意深度的嵌套,因此您可以創建您認為對應用程序有意義的任何級別的母版頁。就像具有母版頁的頁面一樣,具有母版頁的母版頁在頂級必須僅包含contentplaceholder控件。在這些contentplaceholder控件內部,母版頁可以添加其他contentplaceholder控件以供實際頁面使用。請注意,引用本身帶有母版頁的母版頁的頁面只能為直接父級母版頁上的contentplaceholder控件提供內容元素。沒有辦法在特定頁面向上兩級或更多級的母版頁上直接填充占位符。作為一個示例,請看一下圖9 中的代碼所示的母版頁定義(metatemplate.master)。

<%@ master %>

<html>
<head>
    <title>
        <asp:contentplaceholder
            runat="server"
            id="_titlecontent"
        >
            standard title
        </asp:contentplaceholder>
    </title>
</head>
<body>
    <form id="_theform" runat="server">
        <h2>header</h2>
        <asp:contentplaceholder runat="server" id="_maincontent" />
        <h2>footer</h2>
    </form>
</body>
</html>

圖9 母版頁定義

    現在,您可以定義另一個母版頁,讓它指定上述母版頁作為它的母版頁,并且為父級母版頁(sitetemplate.master)中的每個contentplaceholder控件提供內容元素,如圖10 所示。

<%@ master masterpagefile="~/metatemplate.master" %>

<asp:content
    runat="server"
    contentplaceholderid="_titlecontent"
>
    <asp:contentplaceholder runat="server" id="_title">
        default title
    </asp:contentplaceholder>
</asp:content>

<asp:content
    runat="server"
    contentplaceholderid="_maincontent"
>
<table>
<tr>
    <td>
        <asp:contentplaceholder
            id="_leftcontent"
            runat="server"
        />
    </td>
    <td>
        <asp:contentplaceholder
            id="_rightcontent"
            runat="server"
        />
    </td>
</tr>
</table>
</asp:content>

圖10 定義一個母版頁

    請注意,為了授予頁面對父級母版頁中_titlecontent占位符的訪問權限,我必須聲明一個content控件,并在其中嵌套一個新的contentplaceholder控件,以授予頁面對父級母版頁中該位置的訪問權限。
小結
    在asp.net 2.0中增加母版頁(人們期盼已久的站點級別模板功能)代表了一個新時代的到來,即人員將能夠更加輕松地創建web站點。開發人員將不必再求助于asp中笨拙的服務器端包含指令或asp.net中復雜的控件層次結構操縱技術。現在,創建可供您的所有其他web頁作為基礎的頁面模板就像設計任何其他普通類型的web頁一樣容易。我敢打賭您已經迫不及待地想要立刻行動了。

    作者簡介:fritz onion是一位專門研究asp.net的獨立顧問、作者和培訓講師。他著有essential asp.net (addison wesley, 2003)一書,并且正在著手撰寫有關asp.net 2.0的第二版。他為developmentor編寫和講授課程,同時還經常在行業會議上發表演講。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 古浪县| 汉源县| 清河县| 渭南市| 琼海市| 剑川县| 都昌县| 临沧市| 庆安县| 三门县| 本溪市| 紫金县| 隆昌县| 漳平市| 新绛县| 镇雄县| 怀柔区| 易门县| 莒南县| 乳源| 老河口市| 方城县| 新巴尔虎左旗| 鹰潭市| 温泉县| 宿松县| 南部县| 陇川县| 萨迦县| 邮箱| 黔西| 府谷县| 岳池县| 界首市| 瑞金市| 乐东| 阿拉善左旗| 德保县| 塘沽区| 印江| 白山市|