2009-10-11 49 views
20

我對WPF比較陌生,有些東西對我來說很陌生。首先,與Windows窗體不同,WPF控件層次結構不支持IDisposable。在Windows窗體中,如果用戶控件使用任何託管資源,則通過覆蓋每個控件實現的Dispose方法來清理資源非常容易。正確清理WPF用戶控件

在WPF中,故事並不那麼簡單。我已經搜索了幾個小時,並且遇到了兩個基本主題:

第一個主題是Microsoft明確指出WPF沒有實現IDisposable,因爲WPF控件沒有非託管資源。雖然這可能是事實,但他們似乎完全錯過了WPF類層次結構的用戶擴展實際上可能使用託管資源(直接或間接通過模型)的事實。通過不實現IDisposable,Microsoft已經有效地移除了唯一可以保證自定義WPF控件或窗口使用的非託管資源得到清理的機制。

其次,我發現Dispatcher.ShutdownStarted幾個引用。我試圖使用ShutdownStarted事件,但它似乎並沒有爲每個控件觸發。我有一堆WPF UserControl,我已經爲ShutdownStarted實現了一個處理程序,並且它永遠不會被調用。我不確定它是否僅適用於Windows,或者WPF App類。然而,它並沒有正確啓動,每次關閉應用程序時我都會打開PerformanceCounter對象。

是否有比Dispatcher.ShutdownStarted事件清理非託管資源更好的選擇?是否有一些技巧來實現IDisposable,以便Dispose被調用?如果可能的話,我更希望避免使用終結器。

回答

12

恐怕Dispatcher.ShutdownStarted確實似乎是唯一的機制,WPF提供了在用戶控件資財。 (見前不久我問過的similar question)。

解決此問題的另一種方法是將所有可支配資源(如果可能的話)從代碼背後移入單獨的類(例如使用MVVM模式時的ViewModel)。然後在更高層次上,您可以處理您的主窗口關閉,並通過Messenger類通知所有ViewModels。

我很驚訝你沒有得到Dispatcher.ShutdownStarted事件。您的UserControls是否在當時連接到頂級窗口?

+4

+1用於將一次性資源移出代碼隱藏。 WPF的關鍵學習點之一是最大限度地減少代碼隱藏,以充分利用數據綁定架構的優勢和表現力。學習是一件痛苦的事情(學習曲線更像攀登懸崖),但是當你「獲得」WPF思維模式時會有所收穫。 – 2009-10-11 13:22:09

+0

所有可支配資源都在ViewModel中,它們本身是IDisposable。我真的很困惑爲什麼Dispatcher.ShutdownStarted事件不會觸發。性能計數器控件(及其關聯的ViewModel)確實附加到WPF圖形中,因爲它嵌入在中。 – jrista 2009-10-11 19:00:14

+1

@Greg D:我通常會得到WPF模型。我一掌握了WPF的基礎知識,就開始使用MVVM,並且我的CodeBehind幾乎和它一樣純粹(僅僅是默認構造函數和對InitializeComponent的調用)。 WPF的可組合性和數據綁定功能非常出色,如果我有選擇,我永遠不會回到Windows窗體。 – jrista 2009-10-11 19:02:13

9

IDisposable接口具有(幾乎)WPF下沒有意義的,因爲機構是從不同的Winforms。在WPF中,你必須記住視覺和邏輯樹:這是根本。
所以,任何視覺對象通常都是作爲其他對象的子對象而存在的。 WPF構建機制的基礎是分層連接可視對象,然後在無用時分離並銷燬。

我想你可能會檢查自UIElement以來暴露的OnVisualParentChanged方法:在連接可視對象和分離時調用此方法。這可能是放置非託管對象(套接字,文件等)的正確位置。

+0

感謝關於OnVisualParentChanged的提示。我會玩,看看它是否有助於解決我的問題。 – jrista 2009-10-11 19:02:51

0

當別人給你關於這個問題的真正有用的信息,還有就是你可能沒有將解釋很多關於爲什麼沒有了IDisposable的一點點信息。基本上,WPF(和Silverlight)大量使用WeakReferences - 這允許您引用GC仍然可以收集的對象。

+0

感謝Pete的洞察力。我很好奇,如果你有一些鏈接,更詳細地解釋這一點?我很好奇WeakReferences有多大用處不會導致問題。他們可以是一個強大的工具在特殊情況下......但我無法想象他們是如何在WPF中使用的。 – jrista 2009-10-11 22:51:11

5

我一直在尋找這也和測試型動物選項後,我實現了威尼斯

protected override void OnVisualParentChanged(DependencyObject oldParent) 
    { 
     if (oldParent != null) 
     { 
      MyOwnDisposeMethod(); //Release all resources here 
     } 

     base.OnVisualParentChanged(oldParent); 
    } 

的解決方案,我意識到,當父母通話Children.Clear()方法,並且已經物品添加到兒童的DependencyObject有一個值。但是當父母添加一個項目(Children.Add(CustomControl))並且子項爲空時,DependencyObject爲null。

+0

我將它改爲if(Parent == null),這樣如果我將控件移動到不同的容器,它不會自毀 – Sean 2017-12-06 21:28:43