共用方式為


WeakEvent 模式

更新:2007 年 11 月

一般應用程式中,在與將處理常式附加到來源的接聽項物件搭配使用時,很可能不會終結附加到事件來源的處理常式。這種情況可能會導致記憶體遺漏 (Memory Leak)。Windows Presentation Foundation (WPF) 引入的特殊設計模式可以用來解決這個問題,方法是藉由提供專屬的管理員類別給特定事件,並在該事件的接聽項上實作介面。這個設計模式稱為「WeakEvent 模式」(WeakEvent Pattern)。

為何要實作 WeakEvent 模式

接聽事件可能會導致記憶體遺漏。一般用於接聽事件的技術,是使用語言特定的語法來附加處理常式到來源事件。例如,C# 中的語法是:source.SomeEvent += new SomeEventHandler(MyEventHandler)。

這個技術會建立事件來源對事件接聽項的強式參考。一般而言,為接聽項附加事件處理常式會讓接聽項的物件存留期 (Lifetime) 受到來源物件存留期的影響 (除非明確移除事件處理常式)。但在有些情況下,您會希望接聽項的物件存留期只受到其他因素的控制,例如接聽項目前是否屬於應用程式的視覺化樹狀結構中,而不希望受到來源的存留期控制。一旦來源物件存留期超過接聽項的物件存留期時,一般的事件模式會導致記憶體遺漏:接聽項存留的時間比預期長。

WeakEvent 模式就是設計來解決這個記憶體遺漏問題。當接聽項需要註冊事件卻無法明確知道移除註冊的時機,或是來源物件存留期超過「有用」的接聽項物件存留期時,就可以使用 WeakEvent 模式 (「有用」的概念是由您定義的)。WeakEvent 模式可以在不以任何方式影響接聽項的物件存留期特性的情況下,允許接聽項註冊和接收事件。實際上,在決定接聽項是否適合記憶體回收時,並不會考慮來源的隱含參考。該參考是弱式參考,因而命名為 WeakEvent 模式和相關的 API。接聽項可以經記憶體回收或由其他方式終結,且來源可以繼續,而不需要保留不可回收的處理常式參考給現在已終結的物件。

哪些人應該實作 WeakEvent 模式

對實作 WeakEvent 模式有興趣的人主要是控制項作者。這是因為身為控制項作者,您主要負責控制項的行為和內含項目,以及控制項對於其插入的應用程式的影響。這包括控制項物件存留期行為,特別是有關所描述的記憶體遺漏問題的處理。

某些案例本身就提供 WeakEvent 模式的應用。一個這類案例是資料繫結,這個情況通常是身為資料來源的來源物件,與身為繫結目標的接聽項物件完全無關。WPF 資料繫結的許多方面,在事件的實作方式上已經有套用 WeakEvent 模式。

如何實作 WeakEvent 模式

實作 WeakEvent 模式包含三個方面:

  • WeakEventManager 類別衍生管理員。

  • 在想要註冊弱式事件接聽項而不要產生來源的強式參考的任何類別上,實作 IWeakEventListener 介面。

  • 註冊接聽項時,對於您想要接聽項使用模式的地方,不要使用事件的普通 add 和 remove 存取子。而改在該事件專屬的 WeakEventManager 中使用 "AddListener" 和 "RemoveListener" 實作。

WeakEventManager

通常您會對於實作模式的事件,建立管理員類別的一對一關係。例如,對於事件 Spin,您會衍生 SpinEventManager 類別做為事件的專屬弱式事件管理員。如果事件存在於一個以上的來源類別中,而且在每個類別中的行為大致相同,並會共用事件資料型別,則可以為每個事件使用相同的管理員。

WeakEventManager 類別衍生作業的實作檢查清單組成如下:覆寫兩個虛擬方法,和公開數個其他成員 (其名稱不是特別由虛擬樣板管理,但仍然存在的)。覆寫作業是用於讓 WPF 基礎結構啟始或結束事件傳遞模式。而其他成員則是提供功能所必要的,這樣您自己的 IWeakEventListener 實作可以使用 WeakEventManager 來附加事件的接聽項。

如需衍生自 WeakEventManager 的詳細實作注意事項,請參閱 WeakEventManager 參考主題中的<繼承者注意事項>。

IWeakEventListener

IWeakEventListener 實作類別只有一個任務:實作介面方法 ReceiveWeakEventReceiveWeakEvent 實作必須是集中式實作,會將該類別上存在的任何事件參考導向適當的 WeakEventManager

如需實作 IWeakEventListener 介面的詳細實作注意事項,請參閱 ReceiveWeakEvent 方法參考主題中的<實作器注意事項>。

附加接聽項

假設您的 ClockwiseSpin 事件 (由 Spinner 定義) 是普通的事件。若要為這個事件使用模式,您應該使用衍生自 WeakEventManager 的現有 ClockwiseSpinEventManager 類別,或是自己實作。如果您的 SpinListener 接聽項類別要成為接聽項,則用於附加處理常式的普通技術 (不是使用模式) 應該使用 += 語法:

spinnerInstance.ClockwiseSpin += new EventHandler(MyOnCWSpinHandler);

但如果您的類別會實作 IWeakEventListener,並負責實作中的 ClockwiseSpin 事件和其管理員,則為 WeakEvent 模式改用的語法是:

ClockwiseSpinEventManager.AddListener(spinnerInstance, this);

接著,針對該事件的處理邏輯是指定在其中一個類別 ReceiveWeakEvent 實作內,而不是普通的委派處理常式。

實作外部事件的模式

WeakEvent 模式有趣的一點是,您可以對程式碼基底 (Code Base) 外的事件實作模式。從來源的觀點來看,處理常式附加到事件的方式沒有不同,並是由 WeakEventManager 控制的。您只需要定義該事件的 WeakEventManager,然後在任何預期要使用模式來接聽該事件的接聽項上,將該事件視為 ReceiveWeakEvent 邏輯的一部分。

請參閱

概念

路由事件概觀

資料繫結概觀

參考

WeakEventManager

IWeakEventListener