溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

C#中怎么實現(xiàn)事件注冊和注銷

發(fā)布時間:2021-07-07 17:27:03 來源:億速云 閱讀:373 作者:Leah 欄目:編程語言

本篇文章給大家分享的是有關(guān)C#中怎么實現(xiàn)事件注冊和注銷,小編覺得挺實用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

C#事件注冊和注銷:設(shè)計思路

主窗體(frmMain :IParentForm)

事件成員:

public event ParentEventHandler OnUserListCreated;

事件處理方法:

void ToDoOnRequestUserList(object sender, EventArgs e){     //創(chuàng)建DataTable dt     …     This.OnUserListCreated(this, new ParentEventArgs(dt));    } 

某一行注冊子窗體事件:

frmChild.OnRequestUserList += new EventHandler (ToDoOnRequestUserList);

子窗體(frmChild)

事件成員:

public event EventHandler OnUserListCreated; 

事件處理方法:

void ToDoOnRequestUserReturned(object sender, ParentEventArgs e){} 

在OnLoad事件處理方法中注冊主窗體的事件:

(this.MdiParent as IParentForm). OnUserListCreated += new ParentEventHandler (ToDoOnRequestUserReturned);

主窗體對象為frmMain,它實現(xiàn)了IParentForm接口,該接口定義了事件成員OnUserListCreated(它的EventArgs為自定義的ParentEventArgs)。frmMain對象在某處創(chuàng)建了一個子窗體frmChild,并注冊了frmChild的事件OnRequestUserList。

子窗體對象frmChild在載入時(OnLoad方法中)獲得frmMain的引用,并注冊了frmMain的事件OnUserListCreated。

根據(jù)業(yè)務(wù)邏輯,子窗體運行的某一時刻,用戶行為觸發(fā)了事件OnRequestUserList,此時frmMain將捕獲此事件并調(diào)用自身的處理方法生成一個被請求的用戶列表(DataTable)。然后,frmMain發(fā)出了事件OnUserListCreated以提示列表生成完畢,并將剛剛創(chuàng)建的DataTable作為ParentEventArgs參數(shù)插入事件中。隨后,子窗體將接收到這個事件,并在自己的事件處理方法中對傳來的DataTable進(jìn)行自己的業(yè)務(wù)邏輯動作。

在接下來程序的運行中,可愛的代碼心情愉悅地順利執(zhí)行…但是,好景不長!

C#事件注冊和注銷:遇到的問題

當(dāng)我將打開的子窗體關(guān)閉后再重新打開,主窗體在觸發(fā)OnUserListCreated事件后發(fā)生調(diào)用目標(biāo)異常,子窗體在該事件的處理方法中也拋出NullReferenceException異常(未將對象引用設(shè)置到對象實例)。當(dāng)我在子窗體的事件處理方法ToDoOnRequestUserReturned中設(shè)置斷點調(diào)試后發(fā)現(xiàn):所有的控件、變量都為null??!

那叫郁悶,那叫惆悵…公車上、步行中、如廁時、入睡前,我估摸著這種靈異現(xiàn)象可能與最近隔壁鄰居家小貓的突然消失有著千絲萬縷的聯(lián)系…當(dāng)然,作為基督教徒的我,也后怕這是主,耶穌基督對于我大前天橫闖馬路的懲罰…

無助中,我極其盲目的在frmChild的ToDoOnRequestUserReturned方法中加入了一行語句:“MessageBox.ShowDialog(“So boring a thing!”)”以發(fā)泄心情。保存、編譯、運行——大壞蛋的面目露了出來!當(dāng)我***次打開子窗體的時候,如我所料,程序正常運行并彈出了MessageBox。關(guān)鍵是,當(dāng)我關(guān)閉子窗口并第二次打開它執(zhí)行時,MessageBox彈出了兩次!恩…

帶著疑問,我重復(fù)了以上關(guān)閉、打開步驟,MessageBox彈出了三次!——事情已經(jīng)有了眉目。在我輾轉(zhuǎn)反復(fù)的思考后(也許有人會罵我菜鳥…),終于明白了所有事情的緣由:

因為程序一直處在運行中,所以主窗體對象一直駐留內(nèi)存中并保持著自身的狀態(tài)(它沒有的disposed),所以,每次子窗體創(chuàng)建時,主窗體都會注冊它的OnRequestUserList事件,同樣的,該子窗體在加載時,自身也會把主窗體的OnUserListCreated事件注冊一次。

問題就出在這里,雖然子窗體關(guān)閉了,并disposed了。但是,它關(guān)閉時并沒有把在主窗體注冊的事件同時注銷。隨著子窗體一次次的打開,主窗體的OnUserListCreated就被+=了N多了注冊用戶,其中的N-1個用戶其實早已經(jīng)不存在了,而主窗體全然不知。所以當(dāng)發(fā)出OnUserListCreated事件后,主窗體還會以無反顧地去調(diào)用這N多個方法代理,這必然會導(dǎo)致異常拋出——***打開的那個子窗體接受到一次次傳來的事件,并企圖調(diào)用ToDoOnUserListReturned方法,如果此方法中包含著對本對象成員變量的操作,自然會引出“未將引用設(shè)置到對象實例”的異常。

也許有朋友會問,為什么主窗體調(diào)用那些早已disposed的frmChild的方法的代理時,會被當(dāng)前存在的那個frmChild執(zhí)行呢?我認(rèn)為這可能是由于類實例的同一個方法在內(nèi)存棧中共享空間造成的;而成員變量在堆中存放,各自維護(hù)其狀態(tài),當(dāng)其所屬的對象被釋放回收時,其值也就置為null了。(個人觀點,望兄弟姐們給予指正)

C#事件注冊和注銷:總結(jié) 

子窗體在關(guān)閉時,應(yīng)當(dāng)把自己注冊的主窗體對象(或者是長久駐留內(nèi)存對象)事件一一注銷。例如本例中,應(yīng)在子窗體的OnClosed事件處理方法中加入以下代碼:

(this.MdiParent as IParentForm). OnUserListCreated -= new ParentEventHandler (ToDoOnRequestUserReturned) 

如果僅僅是為了在主窗體執(zhí)行完某項操作后觸發(fā)子窗體某一方法的執(zhí)行,我們通常不采用事件機制,而采用以下兩種方法:

A. 將此方法訪問屬性改為public,然后由主窗體適時調(diào)用。

B. 定義一個接口,子窗體對象實現(xiàn)這個接口,并把該目標(biāo)方法提升為該接口的成員。由主窗體適時調(diào)用這個接口成員方法。

以上就是C#中怎么實現(xiàn)事件注冊和注銷,小編相信有部分知識點可能是我們?nèi)粘9ぷ鲿姷交蛴玫降?。希望你能通過這篇文章學(xué)到更多知識。更多詳情敬請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI