從使用基本的文本編輯器到創(chuàng)作標(biāo)記頁面,Web 開發(fā)已經(jīng)經(jīng)歷了一個漫長的過程。目前,集成開發(fā)環(huán)境 (IDE) 為開發(fā)過程中的幾乎每個方面都提供了圖形化表示形式。此外,還實現(xiàn)各種說明性 編程 技術(shù)以提高效率并降低出現(xiàn)錯誤的幾率。Visual Studio 2005 和 ASP .NET 2.0 中的控件體系結(jié)構(gòu)遵循了這些編程趨勢,并且提供了可靠的、可擴展的環(huán)境,該環(huán)境 設(shè)計 為使開發(fā)人員可以創(chuàng)建能夠以說明方式配置的控件。
此外,ASP.NET 中新的自適應(yīng)呈現(xiàn)模型減少了編寫可專門識別其目標(biāo)瀏覽器的控件的需要。換句話說,控件開發(fā)人員可以專注于設(shè)計控件,而讓 ASP.NET 框架負(fù)責(zé)轉(zhuǎn)換控件并針對不同類型的瀏覽器和設(shè)備呈現(xiàn)它。
盡管 ASP.NET 2.0 在控件設(shè)計過程中提供了增量改進功能,但實際控件呈現(xiàn)模型已經(jīng)完全進行了更改。作為自定義控件開發(fā)人員,您將會看到利用 ASP.NET 的幾個新選項。最重要的是,您將會發(fā)現(xiàn)只需編寫較少的代碼便可完成相同的任務(wù)。
在 ASP.NET 2.0 中,創(chuàng)建自定義服務(wù)器控件有很多方法,每種方法都有其優(yōu)點和局限性。本文將討論與自定義控件的創(chuàng)建和配置相關(guān)的詳細(xì)信息。代碼示例和體系結(jié)構(gòu)概念要求您對 C# 編程語言具有中等水平的理解。
自適應(yīng)呈現(xiàn)模型
在 ASP.NET 1.x 中,自定義控件開發(fā)人員必須設(shè)計每個服務(wù)器控件,以便它可以識別不同的瀏覽器類型并發(fā)出正確的輸出。ASP.NET 1.x 控件框架提供了幾項功能以使該任務(wù)變得更簡單,但開發(fā)人員仍然必須根據(jù)瀏覽器的類型編寫切換程序、開發(fā)適當(dāng)?shù)? HTML ,然后針對不同類型的瀏覽器測試控件。此外,如果開發(fā)人員希望控件在移動設(shè)備上顯示,他必須創(chuàng)建一個與普通 Web 瀏覽器上使用的控件不同的全新控件。
ASP.NET 2.0 通過新的自適應(yīng)呈現(xiàn)模型簡化了瀏覽器檢測和呈現(xiàn)過程。在 ASP.NET 2.0 中引入的自適應(yīng)呈現(xiàn)模型旨在用于支持那些眾多能夠使用標(biāo)記格式(包括 HTML、WML、XHTML 或 CHMTL)的不同設(shè)備。
自適應(yīng)呈現(xiàn)模型體系結(jié)構(gòu)
每個控件都可以鏈接到一個適配器,它會針對特定的目標(biāo)設(shè)備修改控件的行為和標(biāo)記。例如,HTML 適配器將 ASP.NET 控件生成為標(biāo)準(zhǔn)的 HTML 和 DHTML,以便普通 Web 瀏覽器使用。另一方面,WML 適配器將相同的控件轉(zhuǎn)換成 無線 標(biāo)記語言,以便蜂窩電話或其他移動設(shè)備使用。
|
圖 1. 控件-適配器壽命周期 |
上圖說明了控件方法與適配器方法之間一對一的映射。如果有適配器(如果控件的 Adapter 屬性不為空),執(zhí)行就會在控件和適配器方法之間傳輸,如上圖所示。在生成階段,控件對象或適配器對象都可以生成輸出(通常情況下兩者不同時生成輸出)。通常情況下,如果有適配器,那么適配器的實現(xiàn)將覆蓋控件的實現(xiàn)。在 ASP.NET 2.0 中,自適應(yīng)呈現(xiàn)模型適用于所有 ASP.NET 控件(不僅僅是移動控件),并且允許 ASP.NET 2.0 支持統(tǒng)一的控件體系結(jié)構(gòu)。
實際意義
自適應(yīng)呈現(xiàn)模型的實際意義有兩個主要方面。第一,作為開發(fā)人員,您可以一次設(shè)計控件并期望它可以在具有適配器的任何類型的設(shè)備或瀏覽器上使用。第二,您可以對常用適配器利用廣泛的 Microsoft 測試,減少您自己瀏覽器的特定測試。
自適應(yīng)呈現(xiàn)模型還為 ASP.NET 2.0 提供了將其他服務(wù)添加到控件生成過程中的機會。由于具有適配器模型,您可以:
1) 根據(jù)目標(biāo)的類型,使用篩選器 來更改控件的外觀。
2) 根據(jù)目標(biāo)的類型,使用模板來更改整個頁面布局。
3) 根據(jù)瀏覽器控制在瀏覽器上的呈現(xiàn),而不必依賴于 ASP.NET 1.x 的 uplevel/downlevel 確定。
在本文中,我們將重點放在創(chuàng)建自定義控件的應(yīng)用方面。但是,請牢記自適應(yīng)呈現(xiàn)模型是新的基礎(chǔ)框架。
創(chuàng)建自定義服務(wù)器控件
Visual Studio 2005 提供了很多用于開發(fā)自定義服務(wù)器控件的有用工具。為了說明某些功能,我們將創(chuàng)建一個 MailLink 控件,它公開了兩個屬性:Email 和 Text。該控件將生成必需的 HTML 來將所提供的 Text 包裝到 mailto: 鏈接標(biāo)記中。
創(chuàng)建項目
在 Visual Studio 2005 中,我們通過在新建項目向?qū)е羞x擇適當(dāng)?shù)膱D標(biāo)來創(chuàng)建一個新的“Web Control Library”項目:
|
圖 2. Visual Studio 2005 中的新建項目向?qū)? |
該項目是利用默認(rèn)的自定義控件類實現(xiàn)創(chuàng)建的。對于我們的示例,我們將該默認(rèn)文件重命名為 MailLink.cs。
注:在解決方案資源管理器中重命名該文件時,Visual Studio 2005 將會自動更新類名。
MailLink 的源代碼在由項目向?qū)傻哪J(rèn)模板上構(gòu)建。MailLink 類從 WebControl 基類自動派生。
| public class MailLink : WebControl { |
WebControl 類提供默認(rèn)實現(xiàn)方法,可以很簡單地覆蓋這些方法來為我們的控件提供詳細(xì)說明。
添加屬性
在 MailLink 示例中,我們需要添加 Email 和 Text 屬性。為了正確配置這些屬性,我們不僅必須編寫代碼,還要分配幾個特性。
|
[Bindable(true),
Category("Appearance"), DefaultValue(""), Description("The e-mail address.")] public virtual string Email { get { string s = (string)ViewState["Email"]; return (s == null) ? String.Empty : s; } set { ViewState["Email"] = value; } } |
特性(以粗體表示)定義了新控件將如何與
設(shè)計
器 (Visual Studio) 進行交互。Email 屬性的特性告訴 Visual Studio 如何在設(shè)計過程中處理屬性:
1) Bindable — Email 屬性可綁定 到數(shù)據(jù)源。您可以將 Email 字段鏈接到
數(shù)據(jù)庫
、
XML
文件或任何其他 DataSet。該特性強制 Visual Studio 在控件的可綁定屬性列表中顯示 Email 屬性。
2) Appearance —Email 屬性將顯示在 Appearance 類別下的屬性視圖中。您可以選擇想要的任何類別,包括默認(rèn)類別:Appearance、
Access
ibility、Behavior、Data、Layout 或 Misc。只要用戶選擇了屬性的類別組織方法,Email 屬性將會顯示在 Appearance 下。
3) DefaultValue — Email 屬性具有一個空的默認(rèn)值。盡管空值對于 Email 字段來說有意義,但對于您添加到控件中的其他屬性可能并不合適。當(dāng)用戶將您的控件放到他們的 Web 頁上時,選擇適當(dāng)?shù)哪J(rèn)值可為用戶免去不計其數(shù)的單擊操作。
4) Description — 屬性說明顯示在控件列表下,并且也可能作為工具提示出現(xiàn)。Email 屬性將具有 The e-mail address 說明。
5) Localizable — 它會用發(fā)送信號的方式通知
ASP.NET
2.0
Framework
該控件包括可以針對不同語言或位置進行配置的文本屬性。
您可以使用 System.ComponentModel 命名空間中的各種特性來進一步改進任何特殊屬性的外觀和行為。我們將在本文的使用設(shè)計器部分中更詳細(xì)地介紹修改屬性或控件的行為的方法。
接下來,我們需要添加 Text 屬性。Text 屬性與 Email 屬性稍有不同,因為我們希望將 Text 顯示為由 MailLink 控件發(fā)出的
HTML
的一部分。為此,我們需要從 System.Web.UI 命名空間中添加一個新的特性。
|
[Bindable(true),
Category("Appearance"), DefaultValue(""), Description("The text to display on the link."), Localizable(true), PersistenceMode(PersistenceMode.InnerDefaultProperty)] public virtual string Text { get { string s = (string)ViewState["Text"]; return (s == null) ? String.Empty : s; } Set { ViewState["Text"] = value; } } |
Text 屬性的 PersistenceMode(PersistenceMode.InnerDefaultProperty) 特性(粗體代碼)指定設(shè)計器應(yīng)該將該屬性作為控件標(biāo)記內(nèi)的內(nèi)部內(nèi)容序列化。該特性還聲明 Text 是控件的默認(rèn)屬性。當(dāng)用戶在 Visual Studio 中使用這個控件時,Text 屬性將會作為該控件的內(nèi)部文本自動顯示在圖形設(shè)計器上,并且如果用戶單擊該控件并嘗試更改顯示的文本,Text 屬性將會自動更改。
另一方面,應(yīng)用到屬性的特性會影響設(shè)計期間用戶與控件的交互方式。在運行過程中,這些特性被
ASP
.NET
運行時忽略。
有關(guān) ViewState 的注釋
請注意,用于兩個屬性的 Get 和 Set 方法都利用 ViewState 對象。ViewState 對象是一個內(nèi)置到 WebControl 類中的幫助器對象。從開發(fā)角度講,ViewState 可被視為一個集合類,用于存儲在回發(fā)過程中我們想要保留的任意屬性。實際上,ViewState 封裝了確定如何執(zhí)行持久性(使用 Cookie、會話等等)所需的所有代碼和邏輯。
生成控件
在定義了控件屬性之后,接下來的步驟就是要
設(shè)計
將由控件發(fā)出的實際響應(yīng)。在 MailLink 示例中,我們希望設(shè)計控件來生成基本的
HTML
標(biāo)記。
TagKey
WebControl 的默認(rèn)實現(xiàn)會生成一個 標(biāo)記。我們的 MailLink 控件通過為 TagKey 屬性提供它自己的實現(xiàn)來覆蓋該默認(rèn)實現(xiàn)。TagKey 屬性定義將要封裝控件內(nèi)容的最外面的標(biāo)記。
幸運的是,我們可以使用 HtmlTextWriterTag 枚舉來指示鏈接 標(biāo)記,而不必實際編寫 HTML 文本。該枚舉方法用于最常用的 HTML 標(biāo)記。
|
protected override HtmlTextWriterTag TagKey {
get { return HtmlTextWriterTag.A; } } |
如果您需要生成一個不屬于 HtmlTextWriterTag 枚舉的一部分的標(biāo)記,您必須覆蓋 WebControl.TagName 屬性,而非 TagKey 屬性。TagName 屬性會返回由控件生成的實際 HTML 標(biāo)記字符串。TagName 的默認(rèn) WebControl 實現(xiàn)只調(diào)用 TagKey,并以完美的提取方式提取正確的 HTML。
AttributesToRender
在定義了基本標(biāo)記之后,接下來的步驟就是分配我們要添加到該標(biāo)記中的各種特性。我們的 MailLink 控件將覆蓋 AddAttibutesToRender 方法以便為“mailto”標(biāo)記添加適當(dāng)?shù)臉?biāo)記。
|
protected override void AddAttributesToRender(
HtmlTextWriter writer){ base.AddAttributesToRender(writer); writer.AddAttribute(HtmlTextWriterAttribute.Href, "mailto:" + Email); } |
對基類的 addAtributeToRender() 調(diào)用會被調(diào)用,以確保可以正確生成其他樣式和特性。如果我們忽略該基本調(diào)用,我們可能會失去內(nèi)置到所有 Web 控件中的母版頁設(shè)計、篩選器或其他功能。
RenderContents
最后,由于所需的 WebControl 類的方法和屬性都已被覆蓋,因此可以使用 RenderContents 方法來編寫文本。出于
安全
原因,MailLink 使用 HtmlTextWriter.WriteEncodedText 方法編寫 HTML 編碼輸出。HTML 編碼安全地將潛在的危險字符轉(zhuǎn)換為更安全的表示形式。
|
protected override void RenderContents(
HtmlTextWriter writer) { if (Text == String.Empty) { Text = Email; } writer.WriteEncodedText(Text); } |
請注意,我們只生成 Text 屬性。如果 Text 屬性為空,我們將利用 Email 屬性填充它。請記住,Text 屬性旨在用作控件標(biāo)記的內(nèi)部文本。這種類型的控件至少需要某一可顯示的文本(以便用戶進行單擊)。如果我們試圖生成一個空字符串,我們將失去鏈接標(biāo)記的預(yù)期功能。
如何生成的?
Render() 方法基本上控制著 WebControl 的整個輸出。默認(rèn)情況下,Render() 方法實際上會依次調(diào)用 RenderBeginTag()、RenderContents() 以及 RenderEndTag()。盡管在
ASP.NET
1.x 中調(diào)用結(jié)構(gòu)并未變化,但由于該呈現(xiàn)模型,修改這些調(diào)用的影響卻發(fā)生了變化。
您可以覆蓋 Render() 方法來發(fā)出您想要的任何內(nèi)容。換句話說,您可能已經(jīng)跳過了覆蓋 TagKey 屬性、AttributestoRender 屬性和 RenderContents() 方法,并且僅使 Render() 編寫“text”。但是,這種做法可能會嚴(yán)重影響自適應(yīng)呈現(xiàn)。如果重寫 Render() 來直接發(fā)出最終輸出,您會繞過內(nèi)置到 WebControl 類中的大多數(shù)自適應(yīng)呈現(xiàn)特性。
自適應(yīng)呈現(xiàn)模型和各種適配器的作用是:截獲對各種標(biāo)記方法的調(diào)用并轉(zhuǎn)換特定設(shè)備的輸出。在 MailLink 的特定示例中,幾乎所有的標(biāo)記語言都支持用于 鏈接的相同語法。但是,其他標(biāo)記通常在不同的標(biāo)記語言中會有截然不同的轉(zhuǎn)換。如果我們?yōu)檫@樣的標(biāo)記使用了 Render(),我們的控件將只能在某些瀏覽器上使用,而適配器無法更改該行為。通過設(shè)計控件以使用自適應(yīng)元素而不是使用 Render(),您可以讓
ASP
.NET
框架有機會根據(jù)瀏覽器提供在瀏覽器上的呈現(xiàn)服務(wù)。
使用自定義控件
自定義控件能夠以很多方法包括在 Web 應(yīng)用程序中。標(biāo)準(zhǔn)方法是將自定義控件編譯到一個程序集中,然后在使用該控件的所有 Web 應(yīng)用程序中添加一個對該程序集的引用。
使用 EmailLink
為了使用 EmailLink 控件,您需要:
1.將 MyControls 項目編譯到一個程序集中。
|
圖 3. 編譯包含 EmailLink 控件的 MyControls 命名空間 |
2.在新的 Web 項目中添加一個對已編譯程序集的引用。
|
圖 4. 編譯應(yīng)用程序并添加一個引用 |
在正確添加引用之后,自定義控件應(yīng)該出現(xiàn)在工具箱中的“MyControls Components”下。
|
圖 5. 工具箱中的 EmailLink |
MyControls 程序集中的所有組件都使用默認(rèn)的齒輪圖標(biāo),因為我們未曾在每個控件上設(shè)置特定的圖標(biāo)。設(shè)置圖標(biāo)如同在該控件類上調(diào)整圖標(biāo)屬性那樣簡單。
頁面上的控件
在添加了對包含控件的程序集的引用之后,您可以將 MailLink 控件拖動到
設(shè)計
器表面并像使用任何其他
ASP.NET
服務(wù)器控件那樣使用它。
|
圖 6. MailLink 自定義控件 |
圖 6 展示了 MailLink 控件的設(shè)計器視圖。請注意,Properties 窗口公開了預(yù)期的 Email 和 Text 元素,它們可以用于配置控件。通過將自定義控件編譯到可重復(fù)使用的程序集中,MailLink 控件可以被很多 Web 應(yīng)用程序重復(fù)使用。
創(chuàng)建復(fù)合服務(wù)器控件
諸如 Login 和 GridView 這些可靠的控件是由很多基本控件組成的。在
ASP
.NET
1.x 中,您必須通過艱苦的工作將嵌套標(biāo)記和元素添加到自定義控件中來開發(fā)復(fù)合控件。在 ASP.NET 2.0 中,您可以通過擴展 System.Web.UI.WebControls.CompositeControl 類來構(gòu)建復(fù)雜的復(fù)合控件。CompositeControl 類提供了將多個控件的輸出合并到單個統(tǒng)一的控件中所必需的框架。
管理復(fù)合控件比管理基本自定義控件稍微困難一些,因為復(fù)合控件需要一些自定義布局的信息。復(fù)合控件將它們的呈現(xiàn)和事件處理任務(wù)委托給構(gòu)成控件。子組件的所有關(guān)聯(lián)的適配器類也會被自動應(yīng)用。這樣,如果您具有適當(dāng)?shù)倪m配器,復(fù)合控件將會在任何目標(biāo)瀏覽器類型或設(shè)備上正確地呈現(xiàn)。
創(chuàng)建復(fù)合控件
創(chuàng)建復(fù)合控件的初始過程與創(chuàng)建自定義服務(wù)器控件的初始過程相似。但是,該過程還涉及了更多的步驟。在以下示例中,我們將創(chuàng)建一個由 Label 和 TextBox 組成的簡單的復(fù)合 AgeCollector 控件,它旨在收集生日的信息。
復(fù)合控件類應(yīng)該通過從 CompositeControl 繼承開始。
| public class AgeCollector : CompositeControl{} |
定義屬性
對于我們的簡單控件,我們必須為標(biāo)簽 (Prompt) 和文本框 (DateOfBirth) 創(chuàng)建屬性。
|
[Bindable(true), Category("Appearance"),
DefaultValue("Please enter your date of birth:"), Description("Text to prompt user with.") Localizable(true)] public virtual String Prompt { get { string s = (string)ViewState["Prompt"]; return (s == null) ? String.Empty : s; } set { ViewState["Prompt"] = value; } } |
再一次,我們使用特性為屬性提供說明和默認(rèn)值。我們選擇了使提示可以進行本地化,以便該控件無論何時都可以用于要求進行國際化的應(yīng)用程序中。實際的提示可以綁定到包含語言特定文本的資源文件。
還必須定義 DateOfBirth 屬性。但是,我們不是使用 String,而是使用 DateTime 數(shù)據(jù)類型來正確地存儲日期。
|
[Bindable(true), Category("Appearance"),
DefaultValue(""), Description("Date of Birth Input area")] public virtual DateTime DateOfBirth { get { bject o = ViewState["DateOfBirth"]; return (o == null) ? DateTime.Now : (DateTime)o; } set { ViewState["DateOfBirth"] = value; } } |
CreateChildControls 方法
我們的復(fù)合控件由一個標(biāo)簽和一個文本框組成。我們無法使用簡單控件的技術(shù)來顯示這兩個標(biāo)記,除非使用強制方式和 Render() 方法。因為我們希望利用自適應(yīng)呈現(xiàn)并顯示我們的兩個控件,所以我們需要覆蓋內(nèi)置到 CompositeControl 類中的 CreateChildControls() 方法。這種方法使我們可以定義控件,并將我們的復(fù)合控件的屬性傳遞到要顯示的單個控件中。
|
protected override void CreateChildControls() {
//Create and load the label Label lab1 = new Label(); lab1.Text = Prompt; lab1.ForeColor = this.ForeColor; this.Controls.Add(lab1); //Add a line break between the label and text box Literal lit = new Literal(); lit.Text = ""; this.Controls.Add(lit); //Add the Textbox TextBox tb = new TextBox(); tb.ID = "tb1"; tb.Text = DateOfBirth.ToString(); this.Controls.Add(tb); //call the parent method base.CreateChildControls(); } |
請注意,我們必須初始化每個控件、分配所有屬性,然后將控件添加到內(nèi)置到 CompositeControl 類中的 Controls 集合。我們還使用了 Literal 對象將換行符置于標(biāo)簽和控件之間。Literal 對象是非常簡單的控件,您可以使用它在功能元素之間插入原始 HTML 。
請注意,我們還對基本方法進行了調(diào)用,以便確保我們的復(fù)合控件具有內(nèi)置到 CompositeControl 基類中的任何其他功能。尤其是,基本方法會強制 ASP.NET 將 Controls 集合的所有元素添加到控件樹中。如果我們忽略這個調(diào)用,或者將其置于我們方法的頂部,那么復(fù)合控件將不會正確地生成。
完整的 AgeCollector
當(dāng)我們的 AgeCollector 控件生成時, ASP .NET 將在每個子控件上實際調(diào)用適當(dāng)?shù)姆椒ǎ⒔Y(jié)果合并到復(fù)合控件的輸出中。換句話說,如果我們已正確地 設(shè)計 了簡單控件,那么該復(fù)合控件就只是一個容器。自適應(yīng)呈現(xiàn)模型將會自動應(yīng)用到每個子控件中。但是,實際的 CompositeControl 將不會被修改,因為它不包含需要更改的任何控件。
以下是另一個實例,其中使用的適當(dāng)方法 (CreateChildControls()) 利用了自適應(yīng)呈現(xiàn)模型,而不是簡單地在 WebControl 上重載 Render() 方法。由于自適應(yīng)呈現(xiàn)模型和 CompositeControl 的特性,ASP.NET 2.0 節(jié)省了我們的開發(fā)時間、減少了代碼行數(shù)并減少了很多的測試煩惱。只要我們知道元素控件可通過特定適配器正確地生成,CompositeControl 將會通過該適配器正確地生成。
如果我們將控件拖動到 ASP.NET 頁面上并查看屬性,我們將會看到具有 Prompt 和 DateOfBirth 屬性的單個控件。
|
圖 7. AgeCollector 使用 |
請注意,如果我們將復(fù)合控件的 ForeColor 更改為紅色,我們實際上更改了 Label 的 ForeColor。但是,我們尚未鏈接某些其他屬性。例如,我們無法更改 DateOfBirth 字段的 ForeColor。換句話說,當(dāng)您構(gòu)建一個復(fù)合控件時,您始終需要考慮應(yīng)該公開哪些子控件屬性。
添加控件行為
到目前為止,我們設(shè)計的兩個控件都是簡單、靜態(tài)的控件。也就是說,這些控件不會完成利用普通的內(nèi)置控件或簡單用戶控件 (.ascx) 無法完成的任何操作。構(gòu)建自定義服務(wù)器控件的主要原因之一就是要提供使用現(xiàn)有控件集無法執(zhí)行的新功能。
事件模型
在 Web 窗體頁面中,與服務(wù)器控件關(guān)聯(lián)的事件由客戶端引發(fā)并由 Web 服務(wù)器處理。對于在客戶機上由服務(wù)器控件引發(fā)的事件,ASP.NET 2.0 事件模型收集有關(guān)請求的信息,并使用 HTTP Post 將詳細(xì)信息傳遞到服務(wù)器。服務(wù)器上的 Page Framework 對該公告作出解釋以確定發(fā)生的事件,然后調(diào)用適當(dāng)?shù)奶幚沓绦蚍椒ā?
|
圖 8. 典型的服務(wù)器控件事件 |
ASP.NET 2.0 可處理幾乎所有捕獲、傳輸和解釋事件的方法。詳細(xì)信息對于開發(fā)人員來說是隱藏的,開發(fā)人員只需要關(guān)心服務(wù)器上的處理程序方法的實現(xiàn)。
大多數(shù)服務(wù)器事件要求一個到服務(wù)器的往返以便進行處理,因此支持有限數(shù)量的單擊類型事件。出于性能原因,不支持鼠標(biāo)懸停和其他內(nèi)部事件。
回發(fā)事件
ASP.NET
2.0 中的很多服務(wù)器控件都生成回發(fā)事件。回發(fā)事件將頁面?zhèn)鬟f到服務(wù)器以便進行處理。這是一個非常昂貴的操作,因為它要求頁面通過網(wǎng)絡(luò)進行傳遞。
回發(fā)模型自從
ASP
.NET
1.x 就沒有進行過顯著更改。為了創(chuàng)建一個可處理回發(fā)的控件,您的控件必須實現(xiàn) IPostBackDataHandler 接口,它定義了兩個方法:
1) LoadPostData — 該方法處理您控件的回發(fā)數(shù)據(jù)。
2) RaisePostDataChangedEvent — 該事件通知應(yīng)用程序由于處理回發(fā)數(shù)據(jù),該控件的狀態(tài)已經(jīng)更改。
PostDataChangedEvent 調(diào)用引發(fā)的事件必須在該控件內(nèi)部定義。然后,用戶可以在開發(fā)過程中編寫實際的事件方法。
非回發(fā)事件
某些服務(wù)器控件支持非回發(fā)事件。此類事件會更改控件的狀態(tài),但并不要求立即進行處理。這些事件由控件緩存,而不是立即傳遞到服務(wù)器以進行處理。例如,ListBox 控件可能包含很多元素。如果用戶選擇一個不同的元素,那么控件將在不通知服務(wù)器的情況下顯示適當(dāng)?shù)母牟⒂涀∑湫聽顟B(tài)。在張貼包含 ListBox 的窗體之后,ListBox 控件將提交事件(選定的項)。
非回發(fā)事件的默認(rèn)行為可以通過設(shè)置 AutoPostBack 屬性進行更改。如果 AutoPostBack 設(shè)置為 true,那么通常由客戶端緩存的事件發(fā)送信號通知服務(wù)器立即進行處理。啟用 AutoPostBack 的控件要求客戶機允許運行腳本。
ASP.NET 2.0 并未以任何明顯的方式更改該模型。
回調(diào)和帶外請求
標(biāo)準(zhǔn)的 Web
協(xié)議
設(shè)計
用于同步通訊。每個請求接收響應(yīng)的速度與服務(wù)器生成數(shù)據(jù)的速度同樣快。但是,很多任務(wù)都需要帶外 請求,例如同一時間訪問第三方資源。這些請求未處于瀏覽器和 Web 服務(wù)器之間的標(biāo)準(zhǔn)通訊帶區(qū)內(nèi),因此被認(rèn)為是帶外請求。
ASP.NET 1.x 中的帶外
進行帶外數(shù)據(jù)請求的要求提示眾多開發(fā)人員可以創(chuàng)造性地使用可用資源來獲得所需的功能。例如,通過使用 ActiveX 組件和
JavaScript
,開發(fā)人員能夠進行外部 HTTP 調(diào)用而無需完全回發(fā)到服務(wù)器。下面的
Java
Script 示例說明了可以與 ASP.NET 1.x 一起使用的帶外 HTTP 請求。
|
function RetrieveGoogle
FrontPage
() {
var XmlHttp = new ActiveXObject("Msxml2. XML HTTP.4.0"); XmlHttp.Open("GET", "http://www.fakedomain.com", false); XmlHttp.Send(); return XmlHttp.responseText; } |
這種機制的一個缺點就是 XmlHttp.responseText 包含該請求的完整結(jié)果。開發(fā)人員將必須編寫只返回商業(yè)數(shù)據(jù)的特殊頁面,否則響應(yīng)會由于不必要的標(biāo)記而非常龐大。
ASP.NET 2.0 中的帶外
ASP.NET 2.0 概括了 XmlHttp 對象的使用并提供了內(nèi)置的回調(diào)功能。新系統(tǒng)的核心有兩個關(guān)鍵項:System.Web.UI.ICallbackEventHandler 和 Page.GetCallbackEventReference 方法。
Page.GetCallbackEventReference 方法及其重載用于指定將參與回調(diào)事件的 JavaScript 方法。
|
public string GetCallbackEventReference(
Control control, string argument, string clientCallback, string context ); |
上述代碼顯示了 GetCallBackEventReference 所需的最小參數(shù)集,這些參數(shù)將在下面進行詳細(xì)說明。
Control — control 參數(shù)確定實現(xiàn) RaiseCallbackEvent 方法的 ICallbackEventHandler。
Argument — argument 字符串包含客戶端腳本。評估該腳本的結(jié)果將作為 eventArgument 參數(shù)傳遞到 RaiseCallbackEvent。
ClientCallback — clientCallback 參數(shù)包含客戶端事件處理程序的名稱,該處理程序?qū)⒔邮粘晒Ψ?wù)器事件的結(jié)果。
Context — context 參數(shù)包含一個客戶端腳本。評估該腳本的結(jié)果將傳遞到客戶端事件處理程序,該處理程序在 clientCallback 參數(shù)中指定為 context 參數(shù)。
CallbackEventHandler 和 GetCallbackEventReference 方法相結(jié)合在客戶端和服務(wù)器之間產(chǎn)生異步通訊。
回調(diào)示例
以下 Web 頁使用回調(diào)機制查詢服務(wù)器以獲得其當(dāng)前時間。該頁面彈出一個
JavaScript
警告,在無需完整頁面回發(fā)的情況下顯示當(dāng)前時間。
|
<%@ Page Language="
C#
" CompileWith="Default3.aspx.cs" ClassName="Default3_aspx" %>
<%@ Register TagPrefix="cc1" Namespace="MyControls" Assembly="WebControlLibrary3" %> <!DOCTYPE html PUBLIC "-//W3C//DTD X HTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <script language="javascript"> function GetServerTime() { var message = ''; var context = ''; <%=CallBack%> } function ShowServerTime(timeMessage, context) { alert('The time on the server is:\n' + timeMessage); } function OnError(message, context) { alert('An unhandled exception has occurred:\n' + message); } </script> </head> <body> <form id="form1" runat="server"> <div> <cc1:timesnap id="TimeSnap1" runat="server"> </cc1:timesnap> <input type="button" value="GetTime" onclick="GetServerTime();" /> </div> </form> </body> </html> |
上述頁面源代碼包含三個關(guān)鍵 Java Script 函數(shù):GetServerTime()、ShowServerTime() 和 OnError()。這些 JavaScript 函數(shù)與頁面的 GetCallbackEventReference 帶外請求相關(guān)聯(lián)。
|
public partial class Default3_aspx {
public string CallBack; void Page_Load(object sender, EventArgs e) { CallBack = this.GetCallbackEventReference(TimeSnap1,"message","ShowServerTime","context","OnError"); } } |
GetCallbackEventReference 方法需要為其第一個參數(shù)實現(xiàn) ICallbackEventHandler 接口的對象。通過實現(xiàn) RaiseCallbackEvent() 方法,TimeSnap 自定義服務(wù)器控件符合接口要求。
|
public class TimeSnap : WebControl, ICallbackEventHandler
{ ... public string RaiseCallbackEvent(string eventArgument) { // Uncomment next line to test error handler // throw new ApplicationException(// "Some unhandled exception"); return DateTime.Now.ToLocalTime().ToShortTimeString(); } } } |
TimeSnap.RaiseCallbackEvent() 方法僅返回 string 格式的當(dāng)前時間。
|
圖 9. 回調(diào)請求輸出 |
圖 9 說明了按下 GetTime 按鈕的結(jié)果。向服務(wù)器發(fā)出帶外請求,從而產(chǎn)生顯示服務(wù)器上當(dāng)前時間的“Alert”窗口。發(fā)出這個請求不需要回發(fā),因此控件的最初生成時間不會改變。
使用 設(shè)計 器
在前面的示例中,我們已經(jīng)使用了幾個標(biāo)準(zhǔn)的特性來規(guī)定自定義控件的屬性將與設(shè)計器 (Visual Studio) 進行交互的方式。我們?yōu)楦鞣N控件屬性分配了特性以定義屬性將在其中出現(xiàn)的類別、定義屬性是否應(yīng)該具有一個默認(rèn)值、定義屬性的說明應(yīng)該是什么樣子以及屬性是否應(yīng)該為 bindable。在 ASP.NET 1.x 中,附加的設(shè)計器類 使您可以創(chuàng)建用于編輯屬性的新對話框、自動將屬性值從 String 轉(zhuǎn)換為其他數(shù)據(jù)類型(反之亦然),并顯示只在運行時生成的控件的占位符數(shù)據(jù)。
設(shè)計器類有助于將控件開發(fā)分成兩個階段。第一,您必須開發(fā)自定義控件。第二,您必須決定開發(fā)人員將如何與設(shè)計環(huán)境內(nèi)的控件進行交互。設(shè)計器類通過在每個自定義控件的頂部充當(dāng)裝飾師來完成第二個任務(wù)。換句話說,如果您要開發(fā)很多自定義控件,您可以創(chuàng)建一個標(biāo)準(zhǔn)的可重復(fù)使用的設(shè)計器集,并通過特性簡單地將設(shè)計器應(yīng)用到每個自定義控件中。
ASP.NET
2.0 為
設(shè)計
器模型提供了幾項增強功能:
1) 新的復(fù)合控件設(shè)計器 — CompositeControlDesiger 類完全識別復(fù)合控件,并且提供支持父子控件關(guān)系的功能。
2) 新的數(shù)據(jù)綁定控件設(shè)計器 — DataBoundControlDesigner 為 Databound 控件提供了很多新功能。您可以使用該設(shè)計器來提供模擬數(shù)據(jù),或者在設(shè)計期間自動連接到活 datasource。
3) 增強的備用設(shè)計時區(qū)域支持 — 新的 DesignerRegion 類及其子類提供了一種非常靈活的機制以便顯示控件。您可以使用 DesignerRegion 來設(shè)置控件的選項卡式視圖。您還可以使用 EditableDesignerRegion 控件為控件創(chuàng)建新的模板。
4) 增強的模板支持 — 現(xiàn)在,設(shè)計器類提供了更簡潔的機制以便將新的模板添加到控件中。模板化控件是一種將控件邏輯和控件顯示分開的控件。顯示通過模板進行定義,而邏輯在實際控件中進行編碼。
5) 增強的任務(wù)支持 — 現(xiàn)在,設(shè)計器可以合并設(shè)計時的任務(wù)。最常見的任務(wù)將可在視圖之間切換。但是,其他任務(wù)可以包括控件的自動配置或資源文件的自動創(chuàng)建。任務(wù)可以在設(shè)計時控件上顯示為菜單(與允許您配置 GridView 控件的菜單相似)。
6) 增強的事件支持 — 設(shè)計器中的事件模型已經(jīng)進行了改進。現(xiàn)在,您可以創(chuàng)建事件來響應(yīng)在不同區(qū)域中的單擊或?qū)Ω鞣N任務(wù)的單擊。使用設(shè)計器時,只要用戶在特定區(qū)域上單擊就可以使控件切換視圖、自動生成代碼或更改配置。
ASP
.NET
2.0 具有一個經(jīng)過顯著改進的設(shè)計器模型,它可以使專業(yè)控件開發(fā)人員的工作更加簡單。如果您只是為自己使用而構(gòu)建一個單個的控件,該設(shè)計器就大材小用了。但是,如果您要為分發(fā)而構(gòu)建一個控件,您可以使用新的設(shè)計器來全面地自定義 Visual Studio 2005 中控件的行為。
小結(jié)
盡管 ASP.NET 2.0 包含了一個內(nèi)容豐富的擴展控件集,但開發(fā)人員通常有很多理由來創(chuàng)建自定義控件。由于 ASP.NET 2.0 中的增強功能,創(chuàng)建自定義控件的過程要比在 ASP.NET 1.x 中更快、更容易。新的 CompositeControl 基類完全利用自適應(yīng)呈現(xiàn)模型,并為創(chuàng)建復(fù)雜的控件提供了一個簡單、易于使用的容器。如果您的控件需要回發(fā)或回調(diào)功能,ASP.NET 2.0 簡化了處理客戶端腳本文件和開發(fā)帶外請求的過程。最后,在您開發(fā)控件后,您可以使用各種設(shè)計器類來完全配置控件在可視化設(shè)計器(例如 Visual Studio 2005)內(nèi)的行為。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

