2009-10-11 137 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