利用 ASP.NET 2.0 創建自定義 Web 控件

Jayesh Patel、Bryan Acker、Robert McGovern
Infusion Development

適用於:
Microsoft ASP.NET 2.0
Microsoft Visual Studio 2005

摘要:ASP.NET 2.0 中新的自適應呈現模型爲控件編寫人員提供了很多新的選項。本文展示了這些選項如何使創建 ASP.NET 的自定義控件變得比以前更加容易。

*
本頁內容
簡介 簡介
自適應呈現模型 自適應呈現模型
創建自定義服務器控件 創建自定義服務器控件
TagKey TagKey
使用自定義控件 使用自定義控件
創建複合服務器控件 創建複合服務器控件
創建複合控件 創建複合控件
添加控件行爲 添加控件行爲
回調示例 回調示例
使用設計器 使用設計器
小結 小結

簡介

從使用基本的文本編輯器到創作標記頁面,Web 開發已經經歷了一個漫長的過程。目前,集成開發環境 (IDE) 爲開發過程中的幾乎每個方面都提供了圖形化表示形式。此外,還實現各種說明性編程技術以提高效率並降低出現錯誤的機率。Visual Studio 2005 和 ASP.NET 2.0 中的控件體系結構遵循了這些編程趨勢,並且提供了可靠的、可擴展的環境,該環境設計爲使開發人員可以創建能夠以說明方式配置的控件。

此外,ASP.NET 中新的自適應呈現模型減少了編寫可專門識別其目標瀏覽器的控件的需要。換句話說,控件開發人員可以專注於設計控件,而讓 ASP.NET 框架負責轉換控件並針對不同類型的瀏覽器和設備呈現它。

儘管 ASP.NET 2.0 在控件設計過程中提供了增量改進功能,但實際控件呈現模型已經完全進行了更改。作爲自定義控件開發人員,您將會看到利用 ASP.NET 的幾個新選項。最重要的是,您將會發現只需編寫較少的代碼便可完成相同的任務。

在 ASP.NET 2.0 中,創建自定義服務器控件有很多方法,每種方法都有其優點和侷限性。本文將討論與自定義控件的創建和配置相關的詳細信息。代碼示例和體系結構概念要求您對 C# 編程語言具有中等水平的理解。

自適應呈現模型

在 ASP.NET 1.x 中,自定義控件開發人員必須設計每個服務器控件,以便它可以識別不同的瀏覽器類型併發出正確的輸出。ASP.NET 1.x 控件框架提供了幾項功能以使該任務變得更簡單,但開發人員仍然必須根據瀏覽器的類型編寫切換程序、開發適當的 HTML,然後針對不同類型的瀏覽器測試控件。此外,如果開發人員希望控件在移動設備上顯示,他必須創建一個與普通 Web 瀏覽器上使用的控件不同的全新控件。

ASP.NET 2.0 通過新的自適應呈現模型簡化了瀏覽器檢測和呈現過程。在 ASP.NET 2.0 中引入的自適應呈現模型旨在用於支持那些衆多能夠使用標記格式(包括 HTML、WML、XHTML 或 CHMTL)的不同設備。

自適應呈現模型體系結構

每個控件都可以鏈接到一個適配器,它會針對特定的目標設備修改控件的行爲和標記。例如,HTML 適配器將 ASP.NET 控件生成爲標準的 HTML 和 DHTML,以便普通 Web 瀏覽器使用。另一方面,WML 適配器將相同的控件轉換成無線標記語言,以便蜂窩電話或其他移動設備使用。

customwebcontrolsaspnet2_fig01

1. 控件-適配器壽命週期

上圖說明了控件方法與適配器方法之間一對一的映射。如果有適配器(如果控件的 Adapter 屬性不爲空),執行就會在控件和適配器方法之間傳輸,如上圖所示。在生成階段,控件對象或適配器對象都可以生成輸出(通常情況下兩者不同時生成輸出)。通常情況下,如果有適配器,那麼適配器的實現將覆蓋控件的實現。在 ASP.NET 2.0 中,自適應呈現模型適用於所有 ASP.NET 控件(不僅僅是移動控件),並且允許 ASP.NET 2.0 支持統一的控件體系結構。

實際意義

自適應呈現模型的實際意義有兩個主要方面。第一,作爲開發人員,您可以一次設計控件並期望它可以在具有適配器的任何類型的設備或瀏覽器上使用。第二,您可以對常用適配器利用廣泛的 Microsoft 測試,減少您自己瀏覽器的特定測試。

自適應呈現模型還爲 ASP.NET 2.0 提供了將其他服務添加到控件生成過程中的機會。由於具有適配器模型,您可以:

根據目標的類型,使用篩選器 來更改控件的外觀。

根據目標的類型,使用模板來更改整個頁面佈局。

根據瀏覽器控制在瀏覽器上的呈現,而不必依賴於 ASP.NET 1.x 的 uplevel/downlevel 確定。

在本文中,我們將重點放在創建自定義控件的應用方面。但是,請牢記自適應呈現模型是新的基礎框架。

創建自定義服務器控件

Visual Studio 2005 提供了很多用於開發自定義服務器控件的有用工具。爲了說明某些功能,我們將創建一個 MailLink 控件,它公開了兩個屬性:EmailText。該控件將生成必需的 HTML 來將所提供的 Text 包裝到 mailto: 鏈接標記中。

創建項目

在 Visual Studio 2005 中,我們通過在新建項目嚮導中選擇適當的圖標來創建一個新的“Web Control Library”項目:


2. Visual Studio 2005 中的新建項目嚮導

該項目是利用默認的自定義控件類實現創建的。對於我們的示例,我們將該默認文件重命名爲 MailLink.cs。

:在解決方案資源管理器中重命名該文件時,Visual Studio 2005 將會自動更新類名。

MailLink 的源代碼在由項目嚮導生成的默認模板上構建。MailLink 類從 WebControl 基類自動派生。

public class MailLink : WebControl  {

WebControl 類提供默認實現方法,可以很簡單地覆蓋這些方法來爲我們的控件提供詳細說明。

添加屬性

MailLink 示例中,我們需要添加 EmailText 屬性。爲了正確配置這些屬性,我們不僅必須編寫代碼,還要分配幾個特性。

[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;
     }
}

特性(以粗體表示)定義了新控件將如何與設計器 (Visual Studio) 進行交互。Email 屬性的特性告訴 Visual Studio 如何在設計過程中處理屬性:

BindableEmail 屬性可綁定 到數據源。您可以將 Email 字段鏈接到數據庫、XML 文件或任何其他 DataSet。該特性強制 Visual Studio 在控件的可綁定屬性列表中顯示 Email 屬性。

AppearanceEmail 屬性將顯示在 Appearance 類別下的屬性視圖中。您可以選擇想要的任何類別,包括默認類別:AppearanceAccessibilityBehaviorDataLayoutMisc。只要用戶選擇了屬性的類別組織方法,Email 屬性將會顯示在 Appearance 下。

DefaultValueEmail 屬性具有一個空的默認值。儘管空值對於 Email 字段來說有意義,但對於您添加到控件中的其他屬性可能並不合適。當用戶將您的控件放到他們的 Web 頁上時,選擇適當的默認值可爲用戶免去不計其數的單擊操作。

Description — 屬性說明顯示在控件列表下,並且也可能作爲工具提示出現。Email 屬性將具有 The e-mail address 說明。

Localizable — 它會用發送信號的方式通知 ASP.NET 2.0 Framework 該控件包括可以針對不同語言或位置進行配置的文本屬性。

您可以使用 System.ComponentModel 命名空間中的各種特性來進一步改進任何特殊屬性的外觀和行爲。我們將在本文的使用設計器部分中更詳細地介紹修改屬性或控件的行爲的方法。

接下來,我們需要添加 Text 屬性。Text 屬性與 Email 屬性稍有不同,因爲我們希望將 Text 顯示爲由 MailLink 控件發出的 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) 特性(粗體代碼)指定設計器應該將該屬性作爲控件標記內的內部內容序列化。該特性還聲明 Text 是控件的默認屬性。當用戶在 Visual Studio 中使用這個控件時,Text 屬性將會作爲該控件的內部文本自動顯示在圖形設計器上,並且如果用戶單擊該控件並嘗試更改顯示的文本,Text 屬性將會自動更改。

另一方面,應用到屬性的特性會影響設計期間用戶與控件的交互方式。在運行過程中,這些特性被 ASP.NET 運行時忽略。

有關 ViewState 的註釋

請注意,用於兩個屬性的 GetSet 方法都利用 ViewState 對象。ViewState 對象是一個內置到 WebControl 類中的幫助器對象。從開發角度講,ViewState 可被視爲一個集合類,用於存儲在回發過程中我們想要保留的任意屬性。實際上,ViewState 封裝了確定如何執行持久性(使用 Cookie、會話等等)所需的所有代碼和邏輯。

生成控件

在定義了控件屬性之後,接下來的步驟就是要設計將由控件發出的實際響應。在 MailLink 示例中,我們希望設計控件來生成基本的 HTML 標記。

TagKey

WebControl 的默認實現會生成一個 標記。我們的 MailLink 控件通過爲 TagKey 屬性提供它自己的實現來覆蓋該默認實現。TagKey 屬性定義將要封裝控件內容的最外面的標記。

幸運的是,我們可以使用 HtmlTextWriterTag 枚舉來指示鏈接 標記,而不必實際編寫 HTML 文本。該枚舉方法用於最常用的 HTML 標記。

protected override HtmlTextWriterTag TagKey {
     get {
        return HtmlTextWriterTag.A;
     }
}

如果您需要生成一個不屬於 HtmlTextWriterTag 枚舉的一部分的標記,您必須覆蓋 WebControl.TagName 屬性,而非 TagKey 屬性。TagName 屬性會返回由控件生成的實際 HTML 標記字符串。TagName 的默認 WebControl 實現只調用 TagKey,並以完美的提取方式提取正確的 HTML。

AttributesToRender

在定義了基本標記之後,接下來的步驟就是分配我們要添加到該標記中的各種特性。我們的 MailLink 控件將覆蓋 AddAttibutesToRender 方法以便爲“mailto”標記添加適當的標記。

protected override void AddAttributesToRender(
  HtmlTextWriter writer){
     base.AddAttributesToRender(writer);
     writer.AddAttribute(HtmlTextWriterAttribute.Href, 
       "mailto:" + Email);
}

對基類的 addAtributeToRender() 調用會被調用,以確保可以正確生成其他樣式和特性。如果我們忽略該基本調用,我們可能會失去內置到所有 Web 控件中的母版頁設計、篩選器或其他功能。

RenderContents

最後,由於所需的 WebControl 類的方法和屬性都已被覆蓋,因此可以使用 RenderContents 方法來編寫文本。出於安全原因,MailLink 使用 HtmlTextWriter.WriteEncodedText 方法編寫 HTML 編碼輸出。HTML 編碼安全地將潛在的危險字符轉換爲更安全的表示形式。

protected override void RenderContents(
  HtmlTextWriter writer) {
    if (Text == String.Empty) {
        Text = Email;
    }
    writer.WriteEncodedText(Text);
}

請注意,我們只生成 Text 屬性。如果 Text 屬性爲空,我們將利用 Email 屬性填充它。請記住,Text 屬性旨在用作控件標記的內部文本。這種類型的控件至少需要某一可顯示的文本(以便用戶進行單擊)。如果我們試圖生成一個空字符串,我們將失去鏈接標記的預期功能。

如何生成的?

Render() 方法基本上控制着 WebControl 的整個輸出。默認情況下,Render() 方法實際上會依次調用 RenderBeginTag()RenderContents() 以及 RenderEndTag()。儘管在 ASP.NET 1.x 中調用結構並未變化,但由於該呈現模型,修改這些調用的影響卻發生了變化。

您可以覆蓋 Render() 方法來發出您想要的任何內容。換句話說,您可能已經跳過了覆蓋 TagKey 屬性、AttributestoRender 屬性和 RenderContents() 方法,並且僅使 Render() 編寫“text”。但是,這種做法可能會嚴重影響自適應呈現。如果重寫 Render() 來直接發出最終輸出,您會繞過內置到 WebControl 類中的大多數自適應呈現特性。

自適應呈現模型和各種適配器的作用是:截獲對各種標記方法的調用並轉換特定設備的輸出。在 MailLink 的特定示例中,幾乎所有的標記語言都支持用於 鏈接的相同語法。但是,其他標記通常在不同的標記語言中會有截然不同的轉換。如果我們爲這樣的標記使用了 Render(),我們的控件將只能在某些瀏覽器上使用,而適配器無法更改該行爲。通過設計控件以使用自適應元素而不是使用 Render(),您可以讓 ASP.NET 框架有機會根據瀏覽器提供在瀏覽器上的呈現服務。

使用自定義控件

自定義控件能夠以很多方法包括在 Web 應用程序中。標準方法是將自定義控件編譯到一個程序集中,然後在使用該控件的所有 Web 應用程序中添加一個對該程序集的引用。

使用 EmailLink

爲了使用 EmailLink 控件,您需要:

1.

MyControls 項目編譯到一個程序集中。

customwebcontrolsaspnet2_fig03

3. 編譯包含 EmailLink 控件的 MyControls 命名空間

2.

在新的 Web 項目中添加一個對已編譯程序集的引用。

customwebcontrolsaspnet2_fig04

4. 編譯應用程序並添加一個引用

在正確添加引用之後,自定義控件應該出現在工具箱中的“MyControls Components”下。

customwebcontrolsaspnet2_fig05

5. 工具箱中的 EmailLink

MyControls 程序集中的所有組件都使用默認的齒輪圖標,因爲我們未曾在每個控件上設置特定的圖標。設置圖標如同在該控件類上調整圖標屬性那樣簡單。

頁面上的控件

在添加了對包含控件的程序集的引用之後,您可以將 MailLink 控件拖動到設計器表面並像使用任何其他 ASP.NET 服務器控件那樣使用它。

customwebcontrolsaspnet2_fig06

6. MailLink 自定義控件

6 展示了 MailLink 控件的設計器視圖。請注意,Properties 窗口公開了預期的 EmailText 元素,它們可以用於配置控件。通過將自定義控件編譯到可重複使用的程序集中,MailLink 控件可以被很多 Web 應用程序重複使用。

創建複合服務器控件

諸如 LoginGridView 這些可靠的控件是由很多基本控件組成的。在 ASP.NET 1.x 中,您必須通過艱苦的工作將嵌套標記和元素添加到自定義控件中來開發複合控件。在 ASP.NET 2.0 中,您可以通過擴展 System.Web.UI.WebControls.CompositeControl 類來構建複雜的複合控件。CompositeControl 類提供了將多個控件的輸出合併到單個統一的控件中所必需的框架。

管理複合控件比管理基本自定義控件稍微困難一些,因爲複合控件需要一些自定義佈局的信息。複合控件將它們的呈現和事件處理任務委託給構成控件。子組件的所有關聯的適配器類也會被自動應用。這樣,如果您具有適當的適配器,複合控件將會在任何目標瀏覽器類型或設備上正確地呈現。

創建複合控件

創建複合控件的初始過程與創建自定義服務器控件的初始過程相似。但是,該過程還涉及了更多的步驟。在以下示例中,我們將創建一個由 LabelTextBox 組成的簡單的複合 AgeCollector 控件,它旨在收集生日的信息。

複合控件類應該通過從 CompositeControl 繼承開始。

public class AgeCollector : CompositeControl
{
}

定義屬性

對於我們的簡單控件,我們必須爲標籤 (Prompt) 和文本框 (DateOfBirth) 創建屬性。

  [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;
            }
        }

再一次,我們使用特性爲屬性提供說明和默認值。我們選擇了使提示可以進行本地化,以便該控件無論何時都可以用於要求進行國際化的應用程序中。實際的提示可以綁定到包含語言特定文本的資源文件。

還必須定義 DateOfBirth 屬性。但是,我們不是使用 String,而是使用 DateTime 數據類型來正確地存儲日期。

  [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 方法

我們的複合控件由一個標籤和一個文本框組成。我們無法使用簡單控件的技術來顯示這兩個標記,除非使用強制方式和 Render() 方法。因爲我們希望利用自適應呈現並顯示我們的兩個控件,所以我們需要覆蓋內置到 CompositeControl 類中的 CreateChildControls() 方法。這種方法使我們可以定義控件,並將我們的複合控件的屬性傳遞到要顯示的單個控件中。

  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();
  }

請注意,我們必須初始化每個控件、分配所有屬性,然後將控件添加到內置到 CompositeControl 類中的 Controls 集合。我們還使用了 Literal 對象將換行符
置於標籤和控件之間。Literal 對象是非常簡單的控件,您可以使用它在功能元素之間插入原始 HTML。

請注意,我們還對基本方法進行了調用,以便確保我們的複合控件具有內置到 CompositeControl 基類中的任何其他功能。尤其是,基本方法會強制 ASP.NET 將 Controls 集合的所有元素添加到控件樹中。如果我們忽略這個調用,或者將其置於我們方法的頂部,那麼複合控件將不會正確地生成。

完整的 AgeCollector

當我們的 AgeCollector 控件生成時,ASP.NET 將在每個子控件上實際調用適當的方法,並將結果合併到複合控件的輸出中。換句話說,如果我們已正確地設計了簡單控件,那麼該複合控件就只是一個容器。自適應呈現模型將會自動應用到每個子控件中。但是,實際的 CompositeControl 將不會被修改,因爲它不包含需要更改的任何控件。

以下是另一個實例,其中使用的適當方法 (CreateChildControls()) 利用了自適應呈現模型,而不是簡單地在 WebControl 上重載 Render() 方法。由於自適應呈現模型和 CompositeControl 的特性,ASP.NET 2.0 節省了我們的開發時間、減少了代碼行數並減少了很多的測試煩惱。只要我們知道元素控件可通過特定適配器正確地生成,CompositeControl 將會通過該適配器正確地生成。

如果我們將控件拖動到 ASP.NET 頁面上並查看屬性,我們將會看到具有 PromptDateOfBirth 屬性的單個控件。

customwebcontrolsaspnet2_fig07

7. AgeCollector 使用

請注意,如果我們將複合控件的 ForeColor 更改爲紅色,我們實際上更改了 LabelForeColor。但是,我們尚未鏈接某些其他屬性。例如,我們無法更改 DateOfBirth 字段的 ForeColor。換句話說,當您構建一個複合控件時,您始終需要考慮應該公開哪些子控件屬性。

添加控件行爲

到目前爲止,我們設計的兩個控件都是簡單、靜態的控件。也就是說,這些控件不會完成利用普通的內置控件或簡單用戶控件 (.ascx) 無法完成的任何操作。構建自定義服務器控件的主要原因之一就是要提供使用現有控件集無法執行的新功能。

事件模型

在 Web 窗體頁面中,與服務器控件關聯的事件由客戶端引發並由 Web 服務器處理。對於在客戶機上由服務器控件引發的事件,ASP.NET 2.0 事件模型收集有關請求的信息,並使用 HTTP Post 將詳細信息傳遞到服務器。服務器上的 Page Framework 對該公告作出解釋以確定發生的事件,然後調用適當的處理程序方法。

customwebcontrolsaspnet2_fig08thumb

8. 典型的服務器控件事件

ASP.NET 2.0 可處理幾乎所有捕獲、傳輸和解釋事件的方法。詳細信息對於開發人員來說是隱藏的,開發人員只需要關心服務器上的處理程序方法的實現。

大多數服務器事件要求一個到服務器的往返以便進行處理,因此支持有限數量的單擊類型事件。出於性能原因,不支持鼠標懸停和其他內部事件。

回發事件

ASP.NET 2.0 中的很多服務器控件都生成回發事件。回發事件將頁面傳遞到服務器以便進行處理。這是一個非常昂貴的操作,因爲它要求頁面通過網絡進行傳遞。

回發模型自從 ASP.NET 1.x 就沒有進行過顯著更改。爲了創建一個可處理回發的控件,您的控件必須實現 IPostBackDataHandler 接口,它定義了兩個方法:

LoadPostData — 該方法處理您控件的回發數據。

RaisePostDataChangedEvent — 該事件通知應用程序由於處理回發數據,該控件的狀態已經更改。

PostDataChangedEvent 調用引發的事件必須在該控件內部定義。然後,用戶可以在開發過程中編寫實際的事件方法。

非回發事件

某些服務器控件支持非回發事件。此類事件會更改控件的狀態,但並不要求立即進行處理。這些事件由控件緩存,而不是立即傳遞到服務器以進行處理。例如,ListBox 控件可能包含很多元素。如果用戶選擇一個不同的元素,那麼控件將在不通知服務器的情況下顯示適當的更改並記住其新狀態。在張貼包含 ListBox 的窗體之後,ListBox 控件將提交事件(選定的項)。

非回發事件的默認行爲可以通過設置 AutoPostBack 屬性進行更改。如果 AutoPostBack 設置爲 true,那麼通常由客戶端緩存的事件發送信號通知服務器立即進行處理。啓用 AutoPostBack 的控件要求客戶機允許運行腳本。

ASP.NET 2.0 並未以任何明顯的方式更改該模型。

回調和帶外請求

標準的 Web 協議設計用於同步通訊。每個請求接收響應的速度與服務器生成數據的速度同樣快。但是,很多任務都需要帶外 請求,例如同一時間訪問第三方資源。這些請求未處於瀏覽器和 Web 服務器之間的標準通訊帶區內,因此被認爲是帶外請求。

ASP.NET 1.x 中的帶外

進行帶外數據請求的要求提示衆多開發人員可以創造性地使用可用資源來獲得所需的功能。例如,通過使用 ActiveX 組件和 JavaScript,開發人員能夠進行外部 HTTP 調用而無需完全回發到服務器。下面的 JavaScript 示例說明了可以與 ASP.NET 1.x 一起使用的帶外 HTTP 請求。

function RetrieveGoogleFrontPage() {
   var XmlHttp = new ActiveXObject("Msxml2.XMLHTTP.4.0");
   XmlHttp.Open("GET", "http://www.fakedomain.com", false);
   XmlHttp.Send();
   return XmlHttp.responseText;
}

這種機制的一個缺點就是 XmlHttp.responseText 包含該請求的完整結果。開發人員將必須編寫只返回商業數據的特殊頁面,否則響應會由於不必要的標記而非常龐大。

ASP.NET 2.0 中的帶外

ASP.NET 2.0 概括了 XmlHttp 對象的使用並提供了內置的回調功能。新系統的核心有兩個關鍵項:System.Web.UI.ICallbackEventHandlerPage.GetCallbackEventReference 方法。

Page.GetCallbackEventReference 方法及其重載用於指定將參與回調事件的 JavaScript 方法。

public string GetCallbackEventReference(
  Control control, 
  string argument, 
  string clientCallback, 
  string context
);

上述代碼顯示了 GetCallBackEventReference 所需的最小參數集,這些參數將在下面進行詳細說明。

Controlcontrol 參數確定實現 RaiseCallbackEvent 方法的 ICallbackEventHandler

Argumentargument 字符串包含客戶端腳本。評估該腳本的結果將作爲 eventArgument 參數傳遞到 RaiseCallbackEvent

ClientCallbackclientCallback 參數包含客戶端事件處理程序的名稱,該處理程序將接收成功服務器事件的結果。

Contextcontext 參數包含一個客戶端腳本。評估該腳本的結果將傳遞到客戶端事件處理程序,該處理程序在 clientCallback 參數中指定爲 context 參數。

CallbackEventHandlerGetCallbackEventReference 方法相結合在客戶端和服務器之間產生異步通訊。

回調示例

以下 Web 頁使用回調機制查詢服務器以獲得其當前時間。該頁面彈出一個 JavaScript 警告,在無需完整頁面回發的情況下顯示當前時間。

<%@ Page Language="C#" CompileWith="Default3.aspx.cs" 
ClassName="Default3_aspx" %>
<%@ Register TagPrefix="cc1" 
  Namespace="MyControls" 
  Assembly="WebControlLibrary3" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 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" 
          οnclick="GetServerTime();" />&nbsp;
    </div>
    </form>
</body>
</html>

上述頁面源代碼包含三個關鍵 JavaScript 函數:GetServerTime()ShowServerTime()OnError()。這些 JavaScript 函數與頁面的 GetCallbackEventReference 帶外請求相關聯。

public partial class Default3_aspx {
  public string CallBack;
  void Page_Load(object sender, EventArgs e) {
    CallBack = this.GetCallbackEventReference(TimeSnap1,
     "message","ShowServerTime","context","OnError");
    }
}

GetCallbackEventReference 方法需要爲其第一個參數實現 ICallbackEventHandler 接口的對象。通過實現 RaiseCallbackEvent() 方法,TimeSnap 自定義服務器控件符合接口要求。

    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 格式的當前時間。

customwebcontrolsaspnet2_fig09

9. 回調請求輸出

9 說明了按下 GetTime 按鈕的結果。向服務器發出帶外請求,從而產生顯示服務器上當前時間的“Alert”窗口。發出這個請求不需要回發,因此控件的最初生成時間不會改變。

使用設計器

在前面的示例中,我們已經使用了幾個標準的特性來規定自定義控件的屬性將與設計器 (Visual Studio) 進行交互的方式。我們爲各種控件屬性分配了特性以定義屬性將在其中出現的類別、定義屬性是否應該具有一個默認值、定義屬性的說明應該是什麼樣子以及屬性是否應該爲 bindable。在 ASP.NET 1.x 中,附加的設計器類 使您可以創建用於編輯屬性的新對話框、自動將屬性值從 String 轉換爲其他數據類型(反之亦然),並顯示只在運行時生成的控件的佔位符數據。

設計器類有助於將控件開發分成兩個階段。第一,您必須開發自定義控件。第二,您必須決定開發人員將如何與設計環境內的控件進行交互。設計器類通過在每個自定義控件的頂部充當裝飾師來完成第二個任務。換句話說,如果您要開發很多自定義控件,您可以創建一個標準的可重複使用的設計器集,並通過特性簡單地將設計器應用到每個自定義控件中。

ASP.NET 2.0 爲設計器模型提供了幾項增強功能:

新的複合控件設計器 — CompositeControlDesiger 類完全識別複合控件,並且提供支持父子控件關係的功能。

新的數據綁定控件設計器 — DataBoundControlDesignerDatabound 控件提供了很多新功能。您可以使用該設計器來提供模擬數據,或者在設計期間自動連接到活 datasource

增強的備用設計時區域支持 — 新的 DesignerRegion 類及其子類提供了一種非常靈活的機制以便顯示控件。您可以使用 DesignerRegion 來設置控件的選項卡式視圖。您還可以使用 EditableDesignerRegion 控件爲控件創建新的模板。

增強的模板支持 — 現在,設計器類提供了更簡潔的機制以便將新的模板添加到控件中。模板化控件是一種將控件邏輯和控件顯示分開的控件。顯示通過模板進行定義,而邏輯在實際控件中進行編碼。

增強的任務支持 — 現在,設計器可以合併設計時的任務。最常見的任務將可在視圖之間切換。但是,其他任務可以包括控件的自動配置或資源文件的自動創建。任務可以在設計時控件上顯示爲菜單(與允許您配置 GridView 控件的菜單相似)。

增強的事件支持 — 設計器中的事件模型已經進行了改進。現在,您可以創建事件來響應在不同區域中的單擊或對各種任務的單擊。使用設計器時,只要用戶在特定區域上單擊就可以使控件切換視圖、自動生成代碼或更改配置。

ASP.NET 2.0 具有一個經過顯著改進的設計器模型,它可以使專業控件開發人員的工作更加簡單。如果您只是爲自己使用而構建一個單個的控件,該設計器就大材小用了。但是,如果您要爲分發而構建一個控件,您可以使用新的設計器來全面地自定義 Visual Studio 2005 中控件的行爲。

小結

儘管 ASP.NET 2.0 包含了一個內容豐富的擴展控件集,但開發人員通常有很多理由來創建自定義控件。由於 ASP.NET 2.0 中的增強功能,創建自定義控件的過程要比在 ASP.NET 1.x 中更快、更容易。新的 CompositeControl 基類完全利用自適應呈現模型,併爲創建複雜的控件提供了一個簡單、易於使用的容器。如果您的控件需要回發或回調功能,ASP.NET 2.0 簡化了處理客戶端腳本文件和開發帶外請求的過程。最後,在您開發控件後,您可以使用各種設計器類來完全配置控件在可視化設計器(例如 Visual Studio 2005)內的行爲。

 
發佈了21 篇原創文章 · 獲贊 1 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章