5

我在silverlight控件上使用了多個Blend行爲和觸發器。我想知道是否有任何機制可以自動分離或確保在不再使用控件(即從可視化樹中移除)時爲行爲或觸發器調用OnDetaching()。爲Silverlight行爲自動調用OnDetaching()

我的問題是,由於其中一種行爲,存在受控制的內存泄漏。該行爲訂閱了OnAttached()覆蓋中某個長壽命對象上的事件,並且應該在OnDetaching()覆蓋中取消訂閱該事件,以便它可以成爲垃圾收集的候選對象。然而,當我從可視化樹中刪除控件時,OnDetaching()似乎永遠不會被調用......唯一能讓它發生的方法是在刪除控件之前明確地分離有問題的行爲,然後正確地進行垃圾收集。

現在我唯一的解決方案是在控制的代碼隱藏中創建一個公共方法,該方法可以通過並分離會導致垃圾收集問題的任何已知行爲。在從面板中刪除控件之前,需要知道要調用此代碼的客戶端代碼。我不太喜歡這種方法,所以我正在尋找一種自動的方式來做到這一點,我忽略了一個更好的建議。

public void DetachBehaviors() 
{ 
    foreach (var behavior in Interaction.GetBehaviors(this.LayoutRoot)) 
    { 
      behavior.Detach(); 
    } 

    //continue detaching all known problematic behaviors on the control.... 
} 

回答

3

你真的需要在這種情況下,什麼是不某種方式自動分離,而是要確保由長期生活的對象舉行的參考不守行爲(以及其他一切有一個參考)從被垃圾收集。

這是通過實施調解員模式來實現的。這個概念是,你不會給這個長壽命的對象一個參考你的Behaviour的代表,而是你創建一個介體類作爲中介。介體附加到長壽命對象事件並保持WeakReference的行爲。當長效對象觸發事件時,中介檢查WeakReference是否仍然存在,如果是,則調用其上的方法來傳遞事件。如果事件發生時介體發現WeakReference不再活動,它將它的事件處理程序從長期存在的對象中分離出來。

因此,沒有什麼能夠阻止垃圾收集的行爲和其他一切事情,剩下的只是一個非常小的中介實例,而死參引仍然附加在長壽命對象上。由於這些調解人很小,他們並不代表真正的問題,即使這些調解人在下次事件發生時也會消失。

幸運的是,你不必自己製造這些東西,而其他人已經做到了。它被稱爲WeakEventListener。這個博客:Highlighting a "weak" contribution; Enhancements make preventing memory leaks with WeakEventListener even easier!有一個很好的關於這個問題的鏈接。

3

Joost van Schaik提供了一種替代方法來清除對附加行爲的引用,同時避免了內存泄漏問題。這取決於使用AssociatedObject的Loaded和Unloaded事件的委託來完成清理工作。

他還提供了用於爲附加行爲生成存根的代碼片段。

+0

謝謝!這種方法適合我們的需求。 – Jaans 2014-01-02 06:16:00

相關問題