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

首頁 > 開發 > 綜合 > 正文

Framework 類庫的事件編程

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


本頁內容
eventhandler 委托
自定義的事件參數
參數化自定義事件
小結

本月的內容是專門介紹事件編程的系列專欄(共三期)的最后一期。在前兩期專欄中,我已經介紹了如何定義和引發事件(請參見 basic instincts:programming with events using .net 和 basic instincts:static event binding using withevents)。我還解釋了如何使用動態和靜態事件綁定來綁定事件處理程序。本月,我將通過一些在 microsoft .net framework 中處理較常用的事件處理實例來總結我對事件的介紹。

eventhandler 委托


當您使用 windows® 窗體或 asp.net 構建應用程序時,您會看到,在所遇到的事件中有相當大的比率是根據一個名為 eventhandler 的通用委托類型定義的。eventhandler 類型存在于 system 命名空間中并具有以下定義:

delegate sub eventhandler(sender as object, e as eventargs)

委托類型 eventhandler 在它的調用簽名中定義了兩個參數。第一個參數(名為 sender)是基于通用 object 類型的。sender 參數用于傳遞指向事件源對象的引用。例如,當 button 對象引發基于 eventhandler 委托類型的事件時,作為事件源的它將傳遞一個對自身的引用。

由 eventhandler 定義的第二個參數名為 e,它是 eventargs 類型的對象。在許多情況下,事件源傳遞的參數值等于 eventargs.empty,這表明沒有額外參數信息。如果事件源希望在 e 參數中傳遞額外的參數化信息,則它應該傳遞一個從 eventargs 類的派生類創建的對象。

圖 1 所示的示例在 windows 窗體應用程序中包含了兩個事件處理程序,它們使用靜態事件綁定來綁定。form 類的 load 事件和 button 類的 click 事件都是根據委托類型 eventhandler 定義的。

您還應該注意到,圖 1中的兩個事件處理程序方法的名稱和格式與 visual studio .net ide 為您生成的一致。例如,如果您在設計視圖中雙擊某個窗體或命令按鈕,visual studio .net 將自動創建類似的事件處理程序方法主干。您需要做的僅僅是填充這些方法的實現,以便為您的事件處理程序賦予預期的行為。

您也許會注意到,visual studio .net ide 是使用 visual basic 6.0 要求的命名方案來生成處理程序方法的。然而,您應當記住的是,visual basic .net 中的靜態事件綁定并不真正與處理程序方法的名稱有關。與其相關的是 handles 子句。您可以隨意將處理程序方法重命名為所需的任何名稱。

您可以重寫這兩個事件處理程序,以便它們使用動態事件綁定(而非靜態事件綁定)來綁定。例如,圖 2 中從 form 派生的類提供了與圖 1中從 form 派生的類完全相同的事件綁定行為。唯一的區別是,后者使用了動態事件綁定,并且不需要 withevents 關鍵字或 handles 關鍵字。在許多情況下,您將根據 eventhandler 委托類型來編寫處理程序方法的實現,而不是引用 sender 參數或 e 參數。例如,當您為從 form 派生的類的 load 事件編寫處理程序時,這些參數值并沒有實際的作用。sender 不會提供任何值,因為它只是傳遞 me 引用。e 參數傳遞 eventargs.empty:

sub form1_load(sender as object, e as eventargs) handles mybase.load
'*** these tests are always true
dim test1 as boolean = sender is me
dim test2 as boolean = e is eventargs.empty
end sub

您也許想知道,為什么 load 事件的調用簽名沒有針對其需要進行更多自定義。畢竟,如果 load 事件根本不包含任何參數,情況將不會這么令人困惑。要找到其他基于 eventhandler 委托類型的事件(并且其 sender 參數或 e 參數不傳遞任何值)的示例很容易。

請回答以下問題。如果該委托類型具有這樣的通用調用簽名,為什么您會認為有這么多事件根據 eventhandler 建模?.net framework 的設計者為什么不根據具有適合其需要的調用簽名的自定義委托來為每個事件建模?如您所知,.net framework 開發中的一個設計目標就是限制用于事件處理的委托的數量。以下幾條是更進一步的解釋。

最小化委托類型數量的第一個目的是,為了更有效地利用應用程序所使用的內存。加載更多類型意味著占用更多內存。如果由 windows 窗體框架中的類定義的每個事件都基于一個自定義委托,則每次運行 windows 窗體應用程序時都必須將上百個委托類型加載到內存中。windows 窗體框架可依賴很少的委托類型在 form 類和各種控件類中定義上百個事件,從而提供更好的內存利用率。

最小化委托類型數量的第二個目的是,利用可插接式處理程序方法來增加實現多態性的可能。當您使用與 eventhandler 委托匹配的調用簽名來編寫處理程序方法時,可以將其綁定到大多數由窗體及其控件引發的事件上。

讓我們來看一些編寫通用事件處理程序的示例。首先介紹這樣一個示例:在這個示例中,可以通過將用戶輸入改為大寫來響應窗體中多個文本框的 textchanged 事件。沒必要為每個控件都創建單獨的事件處理程序。相反,您可以只創建一個事件處理程序,然后將其綁定到多個不同文本框的 textchanged 事件上(請參見圖 3)。

對于這個示例,首先應該注意的是,handles 子句并不僅限于一個事件。您可以在 handles 關鍵字后面使用由逗號分隔的列表來包括任意數量的事件。在本示例中,使用了 textchangedhandler 方法來創建三個不同的事件處理程序。因此,當用戶更改這三個文本框中任意一個的文本時,都將執行這個方法。

當執行 textchangedhandler 方法時,如何知道是哪個 textbox 對象引發該事件呢?這就是 sender 參數要解決的問題。請記住,sender 參數是根據通用類型 object 傳遞的。這意味著,在針對其編程之前,必須將它轉換成一個更具體的類型。在前面的示例中,要訪問 sender 參數的 text 屬性,就必須將該參數轉換為 textbox。

如果您曾經使用 visual basic 的早期版本生成了基于窗體的應用程序,則您可能習慣于使用控件數組。在 visual basic 6.0 中使用控件數組的主要優勢在于,此功能使得創建一個能夠響應由多個不同控件引發的事件的處理程序方法成為可能。visual basic .net 不支持控件數組。然而,您無需過度緊張,因為您剛才已經看到,visual basic .net 提供了一種替代技術,可以將一個處理程序方法綁定到多個不同的事件上。

.net framework 的事件體系結構還為您提供了控件數組無法實現的功能。例如,您可以創建一個處理程序方法來響應由多個不同類型的控件所引發的事件。圖 4 顯示了一個處理程序方法示例,它綁定到三個不同控件類型上的三個不同的事件上。

正如您所看到的,將處理程序方法綁定到事件的方案相當靈活。唯一的要求是,處理程序方法和它綁定到的事件應基于相同的委托類型。而 .net framework 中有相當多的事件都是基于 eventhandler 委托類型的,這使得編寫通用處理程序方法十分簡單。

當您編寫通用處理程序方法時,有時需要編寫代碼來執行條件操作,而這些操作只在事件源是某種特定類型的對象時才執行。例如,您的處理程序方法可以使用 typeof 運算符來檢查 sender 參數。這使得您的處理程序方法可以在事件源為 button 對象時執行一組操作,而在事件源為 checkbox 對象時執行另一組操作,如下所示:

sub generichandler1(sender as object, e as eventargs)
if (typeof sender is button) then
dim btn as button = ctype(sender, button)
'*** program against btn
elseif (typeof sender is checkbox) then
dim chk as checkbox = ctype(sender, checkbox)
'*** program against chk
end if
end sub

返回頁首
自定義的事件參數


基于 eventhandler 委托的事件通知通常不在 e 參數中發送任何有意義的信息。e 參數通常是無用的,因為它包含 eventargs.empty 值或 nothing 值。然而,.net framework 的設計者創建了一個將參數化信息從事件源傳遞到其事件處理程序的約定。此約定包括自定義事件參數類和自定義委托類型的創建。

由 form 類引發的鼠標事件為應該如何使用此約定提供了一個很好的示例。有關鼠標位置和按下哪個鼠標鍵的參數化信息在一個名為 mouseeventargs的類中建模。mouseeventargs 類包含了用于跟蹤鼠標位置的 x 和 y 屬性,以及用于指示按下哪個鼠標鍵的 button 屬性。請注意,按照約定,mouseeventargs 類必須從通用類 eventargs 繼承。

在事件通知中傳遞參數化信息的約定需要一個自定義委托來補充自定義事件參數類。因此,有一個名為 mouseeventhandler 的委托用于補充 mouseeventargs 類。該處理程序委托的定義如下:

delegate sub mouseeventhandler(sender as object, e as mouseeventargs)

現在,假設您希望對一個與鼠標有關的事件(如 form 類的 mousedown 事件)作出響應。您可以編寫如圖 5 所示的處理程序方法。

請注意,e 參數在該處理程序方法的實現中非常有用。e 參數用于確定鼠標位置以及按下哪個鼠標鍵。所有這些參數化信息都可以通過設計 mouseeventargs 類來實現。

您可以找到在 windows 窗體框架中使用的這種參數化約定的其他示例。例如,有一個名為 keypresseventargs 的類,它由一個名為 keypresseventhandler 的委托類型補充。此外,itemchangedargs 類由一個名為 itemchangedhandler 的委托類型補充。您可能會遇到其參數化信息也遵循這個約定的其他事件。

返回頁首
參數化自定義事件


作為練習,我們來設計一個自定義事件,以遵循此約定進行參數化。我將使用一個類似于我在最近幾期專欄中使用的示例,它包括一個 bankaccount 類。請考慮以下代碼片段:

class bankaccount
sub withdraw(byval amount as decimal)
'*** send notifications if required
if (amount > 5000) then
'*** raise event
end if
'*** perform withdrawal
end sub
end class

假設要求 bankaccount 對象在每次遇到提款金額大于 $5,000 的情況時都引發一個事件。在引發該事件時,要求您將提款金額作為參數傳遞給所有已注冊的事件處理程序。首先,您應該創建一個新的事件參數類,它從 eventargs 類繼承:

public class largewithdrawargs : inherits eventargs
public amount as decimal
sub new(byval amount as decimal)
me.amount = amount
end sub
end class

自定義事件參數類應該設計為:對于事件源需要傳遞給其事件處理程序的每個參數化值,它都包含一個公共字段。在本例中,largewithdrawargs 類被設計為包含一個名為 amount 的 decimal 字段。接下來,您必須創建一個新的委托類型以補充新的事件參數類:

delegate sub largewithdrawhandler(byval sender as object, _
byval e as largewithdrawargs)

按照約定,此委托類型被定義為包含一個名為 sender 的 object 參數作為第一個參數。第二個參數 e 則基于自定義事件參數類。

現在,您已經創建了自定義事件參數類和補充的委托類型,可以將它們投入使用了。請考察下面的類定義:

class bankaccount
public event largewithdraw as largewithdrawhandler
sub withdraw(byval amount as decimal)
'*** send notifications if required
if (amount > 5000) then
dim args as new largewithdrawargs(amount)
raiseevent largewithdraw(me, args)
end if
'*** perform withdrawal
end sub
end class

它對 largewithdraw 事件進行了修改,可以使用 .net framework 中的標準約定在事件通知中傳遞參數化信息。當在 withdraw 方法中引發 largewithdraw 事件時,有必要創建一個新的 largewithdrawargs 類實例,并將其作為參數傳遞。由于 bankaccount 對象引發了該事件,所以可以使用 me 關鍵字來傳遞 sender 參數,如下所示:

dim args as new largewithdrawargs(amount)
raiseevent largewithdraw(me, args)

既然您已經了解了如何創建事件源,接下來我們將注意力轉到如何為這個事件創建處理程序方法。處理程序方法應該能夠通過 e 參數檢索它需要的參數化信息。在本例中,處理程序方法將使用 e 參數來檢索 amount 字段的值:

sub handler1(sender as object, e as largewithdrawargs)
'*** retrieve parameterized information
dim amount as decimal = e.amount
end sub

圖 6 顯示了完整的應用程序,當提取大筆金額時,bankaccount 對象將發送事件通知。請注意,此應用程序符合在事件中傳遞參數化信息的標準公共語言運行庫約定。

返回頁首
小結


本節總結了使用 visual basic .net 進行事件編程的基礎知識系列內容。前兩期專欄介紹了引發和處理事件的機制。本月的專欄則著重介紹在 .net framework 中定義的通用事件和委托的編程實例。

您通過 visual basic .net 處理的大多數事件很可能是基于 eventhandler 委托的。如您所見,可以將多個事件綁定到一個處理程序方法上。在這種情況下,知道何時以及如何使用 sender 參數非常重要。您還了解了其他一些使用自定義參數類傳遞參數化信息的事件??傊?,您現在應該可以使用事件驅動的框架(比如 windows 窗體或 asp.net)來進行一些開發工作。


請將給 ted 的問題和意見發送到 [email protected]。

ted pattison 是 developmentor (http://www.develop.com) 的教師兼課程作者。他已經撰寫了幾本關于 visual basic 和 com 的書籍,他目前正在撰寫一本名為 building applications and components with visual basic .net (addison-wesley, 2003) 的書籍。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 西宁市| 介休市| 峡江县| 晋中市| 即墨市| 东平县| 五大连池市| 宜君县| 和平县| 双牌县| 龙江县| 定边县| 乐昌市| 大港区| 临沭县| 台南市| 双城市| 宝丰县| 防城港市| 彭阳县| 安龙县| 铜梁县| 宾川县| 增城市| 彭水| 榕江县| 通州市| 平昌县| 荆门市| 永吉县| 墨竹工卡县| 迁安市| 高淳县| 上饶市| 尼木县| 丁青县| 大悟县| 盱眙县| 顺义区| 称多县| 三台县|