更新:2007 年 11 月
本主題演示如何在 ASP.NET 中創(chuàng)建一個從客戶端 Sys.Component 基類派生的 AJAX 非可視客戶端組件,以及如何在頁中使用該組件。
在本教程中,您將了解如何執(zhí)行以下操作:
-
使用原型設計模式通過 ECMAScript (JavaScript) 定義一個非可視組件類。
-
將非可視組件注冊為從 Component 基類派生的類。
-
初始化非可視組件的 Component 基類并調用其方法。
-
創(chuàng)建引發(fā)更改通知的屬性。
-
在頁中使用組件并綁定到組件的事件。
本概述提供一個計時器示例作為非可視客戶端組件。該計時器引發(fā)可以處理的事件。
本主題重點介紹基于非可視客戶端組件的對象。這些組件從 Component 派生且通常沒有 UI 表示形式。還有另外兩種類型的、擴展基本組件功能的 ASP.NET AJAX 客戶端組件對象:從 Sys.UI.Behavior 派生的行為和從 Sys.UI.Control 派生的控件。下表總結了組件、行為和控件之間的區(qū)別。
客戶端組件對象類型 |
摘要 |
---|---|
組件 |
|
行為 |
|
控件 |
|

若要運行本主題中的示例,您需要:
-
一個支持 AJAX 的 ASP.NET 網(wǎng)站。如果您有一個已配置好的網(wǎng)站,則可以在本示例中使用該網(wǎng)站。有關如何創(chuàng)建虛擬目錄或網(wǎng)站的信息,請參見如何:在 IIS 5.0 和 6.0 中創(chuàng)建和配置虛擬目錄。

ASP.NET AJAX 非可視客戶端組件封裝可跨應用程序重用的 JavaScript 代碼。一個按照設定的時間間隔引發(fā)事件的計時器組件便是非可視組件的一個示例。
通過從 Component 基類派生,自定義組件會自動繼承以下功能:
-
用于管理與客戶端對象事件的處理程序綁定的跨瀏覽器模型。
-
客戶端應用程序中的組件的自動注冊(作為實現(xiàn) Sys.IDisposable 接口的可釋放對象)。
-
在屬性發(fā)生更改時引發(fā)通知事件的功能。
-
對組件屬性設置執(zhí)行批處理操作的功能。與在各個屬性 get 和 set 訪問器中處理所有邏輯相比,此操作在腳本大小和處理時間上更有效。
-
重寫 Sys.Component.initialize 方法以初始化任何屬性和事件偵聽器。

若要實現(xiàn)從 Component 派生的自定義客戶端組件,請按下列步驟操作:
-
使用原型設計模式定義一個組件類。
-
初始化組件的基 Component 實例。
-
公開所有屬性訪問器,并可以選擇引發(fā) propertyChanged 通知事件。
-
重寫 dispose 方法以釋放資源,例如清除事件處理程序。
以下各節(jié)提供了有關實現(xiàn)步驟的詳細信息。
使用原型設計模式定義組件類
ASP.NET AJAX 客戶端類(其中包含一個組件類)是使用原型設計模式通過 JavaScript 定義的。若要通過使用原型設計模式定義組件類,請執(zhí)行以下操作:
-
注冊組件類的命名空間。
-
創(chuàng)建組件的構造函數(shù),并在構造函數(shù)中定義所有私有字段并設置其初始值。
-
定義組件的原型。
-
將組件函數(shù)注冊為從 Component 派生的類。
有關更多信息,請參見使用原型模型創(chuàng)建客戶端組件類。
初始化基類
在組件的構造函數(shù)中,調用繼承的 Type.initializeBase 方法可初始化注冊的類的基類型??蓪⒎强梢暯M件類注冊為其基類型為 Component 的類。如果 Component 基類已初始化,則其方法可供組件使用,并且它會自動在支持 AJAX 的 ASP.NET 應用程序中將組件注冊為可釋放對象。有關更多信息,請參見 Sys.IDisposable 接口。
從 Component 派生的任何組件類都必須使用構造函數(shù)初始化其基類。在構造函數(shù)中運行任何其他代碼之前,通常先調用 initializeBase。下面的示例演示一個從 Component 派生的非可視組件的構造函數(shù)。
Samples.SimpleComponent = function() { Samples.SimpleComponent.initializeBase(this); }
定義屬性和引發(fā)屬性更改通知
在頁開發(fā)人員可以獲取和設置的組件類中定義屬性。從 Component 派生的 ASP.NET AJAX 組件繼承 Sys.Component.raisePropertyChanged 方法,您可以調用該方法以便為您的組件屬性引發(fā) propertyChanged 事件。然后,使用您的組件的網(wǎng)頁開發(fā)人員可以綁定到這些事件。有關更多信息,請參見定義自定義組件屬性和引發(fā) PropertyChanged 事件。
初始化屬性和事件偵聽器
如果自定義組件必須初始化任何屬性或事件偵聽器,則應在組件的原型中重寫 Sys.Component.initialize 方法。例如,從 Component 派生的非可視組件可能會將某個委托分配給一個事件(如 window.onFocus)。最后,調用 initialize 基方法以使組件的基類完成初始化。
ASP.NET 提供了可以為組件和 DOM 元素提供標準事件管理的類和方法。若要管理組件的事件,請使用 Sys.EventHandlerList 類。例如,可以使用 Sys.EventHandlerList.addHandler 方法綁定事件,并使用 Sys.EventHandlerList.removeHandler 方法釋放事件。有關更多信息,請參見 Sys.EventHandlerList 類。
若要管理 DOM 元素或 window 對象的事件處理程序,請使用 Sys.UI.DomEvent 類。例如,可以使用 Sys.UI.DomEvent addHandler 和 Sys.UI.DomEvent removeHandler 方法綁定和取消綁定事件處理程序。有關更多信息,請參見 Sys.UI.DomEvent 類。
釋放資源
如果自定義組件在釋放組件之前必須釋放資源,則重寫 dispose 方法并釋放重寫的方法中的資源。這樣可確保恰好在釋放組件之前釋放資源。應釋放的資源可能包含 DOM 事件的處理程序。通過驗證 DOM 元素和組件對象之間任何可能的循環(huán)引用是否已被移除,確??梢詮膬却嬷幸瞥搶ο蟆S嘘P更多信息,請參見釋放組件資源。

若要在 ASP.NET AJAX 應用程序頁中使用自定義客戶端組件,請執(zhí)行以下操作:
-
在網(wǎng)頁中注冊組件的腳本庫。
-
創(chuàng)建一個組件實例。
以下各節(jié)提供了有關這些步驟的詳細信息。
在網(wǎng)頁中注冊組件的腳本庫
可以使用 ScriptManager 控件,通過聲明方式或編程方式來注冊頁上的客戶端控件所需的腳本。下面的示例演示注冊組件腳本的 ScriptManager 控件的聲明性標記。
<form id="form1" runat="server"> <asp:ScriptManager runat="server" ID="ScriptManager01"> <scripts> <asp:ScriptReference path="DemoTimer.js" /> </scripts> </asp:ScriptManager> </form>
asp:ScriptManager 元素在 scripts 節(jié)點內包含 asp:ScriptReference 元素。asp:ScriptReference 元素的 path 屬性引用定義組件類的 .js 文件(在本示例中為 DemoTimer.js 文件)的路徑。有關更多信息,請參見動態(tài)分配腳本引用和 ScriptManager 類概述。
作為使用 ScriptManager 控件注冊腳本文件的替代方法,可以使用實現(xiàn) IScriptControl 接口的自定義服務器控件來管理客戶端組件。自定義服務器控件可以自動注冊所需的組件腳本,并公開用于設置組件屬性和事件綁定的聲明性標記。如果您使用自定義服務器控件注冊腳本,則頁開發(fā)人員可以更加方便地使用您的組件。有關更多信息,請參見 IScriptControl 類概述。
![]() |
---|
若要使用 ScriptManager 控件注冊的所有獨立腳本文件都必須調用 notifyScriptLoaded 方法,以便通知應用程序腳本已完成加載。嵌入在程序集中的腳本在大多數(shù)情況下不應調用此方法。有關更多信息,請參見 Sys.Application.notifyScriptLoaded 方法。 |
創(chuàng)建自定義組件實例
可通過調用 Sys.Component.create 方法或 $create 快捷方式實例化客戶端組件??上?$create 方法傳遞參數(shù)來指定組件類型。此外,還可傳遞一個 JSON 對象,并在其中包含必需的 ID 值、可選的初始屬性值和可選的事件處理程序綁定。
下面的示例演示如何通過調用 $create 方法實例化組件實例。
var app = Sys.Application; app.add_init(applicationInitHandler); function applicationInitHandler(sender, args) { $create(Demo.Timer, {enabled:true,id:"demoTimer1", interval:2000}, {tick:OnTick}, null); }
有關更多信息,請參見Sys.Component.create 方法和Sys.Component $create 方法。

在本節(jié)中,您將創(chuàng)建一個擴展 Component 基類的名為 Demo.Timer 的自定義客戶端組件,然后在頁中使用該組件。Demo.Timer 是一個簡單的計時器組件,可定義 tick 事件,公開 enabled 屬性和 interval 屬性,以及針對 interval 屬性引發(fā)更改通知事件。使用 Demo.Timer 組件的頁開發(fā)人員可以處理 tick 事件。開發(fā)人員還可以綁定到 property-changed 事件,以便每次更新 interval 屬性時執(zhí)行操作。
為 Demo.Timer 組件創(chuàng)建代碼
-
在支持 AJAX 的 ASP.NET Web 應用程序的根目錄中,創(chuàng)建一個名為 DemoTimer.js 的文件。
-
向文件中添加以下代碼:
Type.registerNamespace("Demo"); Demo.Timer = function() { Demo.Timer.initializeBase(this); this._interval = 1000; this._enabled = false; this._timer = null; } Demo.Timer.prototype = { // OK to declare value types in the prototype get_interval: function() { /// <value type="Number">Interval in milliseconds</value> return this._interval; }, set_interval: function(value) { if (this._interval !== value) { this._interval = value; this.raisePropertyChanged('interval'); if (!this.get_isUpdating() && (this._timer !== null)) { this._restartTimer(); } } }, get_enabled: function() { /// <value type="Boolean">True if timer is enabled, false if disabled.</value> return this._enabled; }, set_enabled: function(value) { if (value !== this.get_enabled()) { this._enabled = value; this.raisePropertyChanged('enabled'); if (!this.get_isUpdating()) { if (value) { this._startTimer(); } else { this._stopTimer(); } } } }, // events add_tick: function(handler) { /// <summary>Adds a event handler for the tick event.</summary> /// <param name="handler" type="Function">The handler to add to the event.</param> this.get_events().addHandler("tick", handler); }, remove_tick: function(handler) { /// <summary>Removes a event handler for the tick event.</summary> /// <param name="handler" type="Function">The handler to remove from the event.</param> this.get_events().removeHandler("tick", handler); }, dispose: function() { // call set_enabled so the property changed event fires, for potentially attached listeners. this.set_enabled(false); // make sure it stopped so we aren't called after disposal this._stopTimer(); // be sure to call base.dispose() Demo.Timer.callBaseMethod(this, 'dispose'); }, updated: function() { Demo.Timer.callBaseMethod(this, 'updated'); // called after batch updates, this.beginUpdate(), this.endUpdate(). if (this._enabled) { this._restartTimer(); } }, _timerCallback: function() { var handler = this.get_events().getHandler("tick"); if (handler) { handler(this, Sys.EventArgs.Empty); } }, _restartTimer: function() { this._stopTimer(); this._startTimer(); }, _startTimer: function() { // save timer cookie for removal later this._timer = window.setInterval(Function.createDelegate(this, this._timerCallback), this._interval); }, _stopTimer: function() { if(this._timer) { window.clearInterval(this._timer); this._timer = null; } } } Demo.Timer.registerClass('Demo.Timer', Sys.Component); // Since this script is not loaded by System.Web.Handlers.ScriptResourceHandler // invoke Sys.Application.notifyScriptLoaded to notify ScriptManager // that this is the end of the script. if (typeof(Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
代碼討論
代碼通過調用 Type.registerNamespace 方法注冊 Demo 命名空間。建議您在構造函數(shù)中聲明并初始化所有私有字段,例如,本示例中的 interval。構造函數(shù)調用繼承的 initializeBase 方法,以便可以使用 Component 基類方法。初始化后的基類又在客戶端應用程序中將 Demo.Timer 實例注冊為一個可釋放對象。
在原型中,代碼聲明并初始化兩個公共屬性:interval 和 enabled。屬性定義包含用于存儲屬性值的私有字段,以及每個屬性的 get 和 set 訪問器。在每個公共屬性的 set 訪問器方法中,代碼通過調用 raisePropertyChanged 方法引發(fā) propertyChanged 事件。每當屬性發(fā)生更改時,此事件都會通知頁開發(fā)人員。
通過 add_tick 和 remove_tick 方法,頁開發(fā)人員可以添加和移除偵聽 tick 事件的方法。通過組件的 Sys.EventHandlerList 集合,這些方法又轉而添加或移除指定的處理程序。EventHandlerList 對象通過繼承的 Sys.Component.events 屬性包含組件的事件處理程序的集合。在示例中,代碼調用返回的 EventHandlerList 對象的 Sys.EventHandlerList.addHandler 和 Sys.EventHandlerList.removeHandler 方法,以便添加或移除指定的處理程序。
Demo.Timer 類重寫基類的 dispose 方法以更新 enabled 屬性并通知使用者該組件已被禁用。enabled 屬性的 set 訪問器引發(fā) propertyChanged 事件來發(fā)送通知。代碼調用私有 _stopTimer 方法阻止引發(fā) tick 事件。最后,代碼調用基 dispose 方法以使應用程序可以釋放該組件。

可以通過自定義服務器控件或通過在網(wǎng)頁中使用客戶端腳本,管理頁中的 ASP.NET AJAX 客戶端組件的實例。在本節(jié)中,您將學習如何使用網(wǎng)頁中的客戶端腳本創(chuàng)建組件實例。
創(chuàng)建使用 Demo.Timer 組件的頁
-
在放置 DemoTimer.js 文件的目錄中,創(chuàng)建一個名為 DemoTimer.aspx 的文件并在其中添加下列標記和代碼:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www./TR/xhtml11/DTD/xhtml11.dtd"> <html > <head runat="server"> <title>Demo Timer Component</title> </head> <body> <form id="form1" runat="server"> <div> <asp:ScriptManager ID="ScriptManager1" runat="server"> <Scripts> <asp:ScriptReference Path="DemoTimer.js"/> </Scripts> </asp:ScriptManager> Timer Tick Count: <span id="result">0</span> </div> <script type="text/javascript"> function OnTick(sender, args) { var result = $get("result"); result.innerText = parseInt(result.innerText) + 1; } var app = Sys.Application; app.add_init(applicationInitHandler); function applicationInitHandler(sender, args) { // Create the DemoTimer component instance. // Set properties and bind events. $create(Demo.Timer, {enabled:true,id:"demoTimer1",interval:2000}, {tick:OnTick}, null, null); } </script> </form> </body> </html>
-
在同一目錄中,創(chuàng)建一個名為 TestDemoTimer.js 的文件并在其中添加以下代碼:
function OnTick(sender, args) { var result = $get("result"); result.innerText = parseInt(result.innerText) + 1; } var app = Sys.Application; app.add_init(applicationInitHandler); function applicationInitHandler(sender, args) { // Create the DemoTimer component instance. // Set properties and bind events. $create(Demo.Timer, {enabled:true,id:"demoTimer1",interval:2000}, {tick:OnTick}, null, null); }
代碼討論
示例頁通過使用包含兩個函數(shù)(OnTick 和 applicationInitHandler)的 JavaScript 代碼加載 TestDemoTimer.js。OnTick 函數(shù)處理 Demo.Timer 組件的 tick 事件并更新 <span> HTML 元素中的計數(shù)器值。
applicationInitHandler 函數(shù)是 app_init 事件的處理程序。在該函數(shù)中,通過調用 $create 方法并傳遞下列參數(shù),在客戶端腳本中實例化 Demo.Timer 組件:
-
type 參數(shù)是先前創(chuàng)建的 Demo.Timer 類。
-
properties 參數(shù)由 JSON 對象組成,該對象包含必需的組件 ID 值,后跟使用初始值指定屬性名稱的屬性名稱/值對。出于演示的目的,interval 屬性最初設置為 2000 毫秒,以便計時器每兩秒引發(fā)一次 tick 事件。(在成品應用程序中,可能會將間隔設置為較大值,以減少網(wǎng)絡通信量。)將該組件的 enabled 屬性設置為 true,以便在實例化該組件之后立即啟動計時器。
-
events 參數(shù)包含一個對象,該對象包含與事件處理程序配對的事件名稱。在這種情況下,onTick 處理程序將分配給在頁的 script 元素中定義的 tick 事件。
DemoTimer.aspx 文件是一個承載該組件的 ASP.NET 網(wǎng)頁。在頁的 ScriptManager 控件中,<asp:ScriptReference> 元素的 path 屬性引用定義 Demo.Timer 組件類的 DemoTimer.js 文件的路徑。