2011-06-14 167 views
2

當我第一次開始寫WPF的自定義控件,如果我想添加事件處理程序,我將在控件的OnApplyTemplate重寫這樣做,得到了模板部件後:刪除事件處理程序

public void override OnApplyTemplate() { 
    if (addMenu != null) { 
    addMenu.Click -= addMenu_Click; 
    addMenu = null; 
    } 
    addMenu = (MenuItem)Template.FindName("PART_AddMenu", this); 
    addMenu.Click += addMenu_Click; 
} 

但是後來有一天我注意到OnApplyTemplate()並不總是在我期望的時候被調用,也就是說,當控件從視覺樹中斷開時。也就是說,使用上述技術,事件處理程序不會總是被刪除。所以我想出了一個不同的方式:

public MyCustomControl() 
{ 
    Loaded += this_Loaded; 
} 

void this_Loaded(object sender, RoutedEventArgs e) 
{ 
    Unloaded += this_Unloaded; 

    addMenu = (MenuItem)Template.FindName("PART_AddMenu", this); 
    addMenu.Click += addMenu_Click; 
} 

void this_Unloaded(object sender, RoutedEventArgs e) 
{ 
    Unloaded -= this_Unloaded; 

    if (addMenu != null) 
    { 
    addMenu.Click -= addMenu_Click; 
    addMenu = null; 
    } 
} 

這種方式似乎有伎倆。是否每個人都認爲這是在自定義控件中連接和刪除事件處理程序的更好方法?如果不是,那爲什麼?

回答

2

這種方法沒問題,但您必須明白,您有時會得到卸載事件,您可能不希望事件處理程序解除掛鉤。例如,假設您有一個選項卡控件。當切換TabItem時,前面的TabItem的內容全部獲得Unloaded,然後在再次選擇TabItem時重新加載。對於像Button.Click這樣的事物來說,這很好,因爲您無法在非活動選項卡上執行此類操作,但即使項目仍然存在,任何不需要將項目加載到可視化樹中的事件都將被斷開連接。

爲什麼你覺得你需要清理所有事件處理程序?我意識到有些情況下,他們可以掛在另一個對象的引用上,但這是一種不尋常的情況,通常最好通過清理它們來處理。這裏有一些更好的細節:How built-in WPF controls manage their event handlers to an attached event?

+0

你是對的,我想防止掛在引用,因爲我已經注意到它發生在性能調整過程中。我不確定具體的原因,所以我寧願使用新技術來安全地玩。關於你的TabItem例子,我知道發生了什麼,但我想不出一個問題。 – HappyNomad 2011-06-15 13:18:54

+0

只有父對象將其事件解析爲子對象時纔會發生泄漏(從而保留對子對象的第二次引用)。 – 2011-06-15 14:40:54

+0

如果我正確地關注你,那麼在上面的例子中,「父對象」是自定義控件,「子對象」是addMenu(模板部分)。由於自定義控件將addMenu存儲在專用字段中,因此舊技術(使用OnApplyTemplate)會發生泄漏。 – HappyNomad 2011-06-15 20:32:33