代码之家  ›  专栏  ›  技术社区  ›  jrista

正确清理WPF用户控件

  •  21
  • jrista  · 技术社区  · 15 年前

    我对水渍险比较陌生,有些东西对我来说很陌生。首先,与Windows窗体不同,WPF控件层次结构不支持IDisposable。在Windows窗体中,如果用户控件使用了任何托管资源,则很容易通过重写每个控件实现的Dispose方法来清理资源。

    在WPF中,这个故事并不那么简单。我搜索了几个小时,遇到了两个基本主题:

    第一个主题是Microsoft明确声明WPF不实现IDisposable,因为WPF控件没有非托管资源。虽然这可能是真的,但他们似乎完全忽略了这样一个事实:用户对其WPF类层次结构的扩展可能确实使用托管资源(直接或间接通过模型)。通过不实现IDisposable,Microsoft已经有效地删除了唯一保证的机制,通过该机制,自定义WPF控件或窗口使用的非托管资源可以被清除。

    其次,我发现了一些对dispatcher.shutdownstarted的引用。我试过使用ShutdownStarted事件,但似乎并不是每个控件都能触发它。我有很多wpf用户控件,我已经实现了一个shutdownstarted的处理程序,它永远不会被调用。我不确定它是否只适用于Windows,或者WPF应用程序类。但是,它没有正确启动,每次应用程序关闭时,我都会泄漏open-performanceCounter对象。

    是否有比Dispatcher.ShutdownStarted事件更好的方法来清除非托管资源?实现IDisposable是否有一些技巧,以便调用Dispose?我更喜欢 避免 尽可能使用终结器。

    4 回复  |  直到 11 年前
        1
  •  12
  •   Community Nick Dandoulakis    7 年前

    恐怕Dispatcher.ShutdownStarted确实是WPF提供的处理用户控件中资源的唯一机制。(看到一个非常 similar question 我刚才问过)。

    解决这个问题的另一种方法是将所有可释放的资源(如果可能的话)从代码中移出,并移动到单独的类中(例如使用MVVM模式时的ViewModel)。然后在更高的层次上,您可以处理主窗口关闭,并通过一个messenger类通知所有的视图模型。

    我很惊讶你没有得到调度员。关闭了启动事件。您的用户控件当时是否附加到顶级窗口?

        2
  •  10
  •   Lance Roberts    12 年前

    IDisposable接口在wpf下几乎没有意义,因为其机制不同于winforms。在WPF中,您必须记住可视化和逻辑树:这是基本的。
    所以,任何视觉对象通常都是作为其他对象的子对象来生活的。WPF构建机制的基础是分层地附加可视对象,然后在它们不可用时分离和销毁。

    我想你可以查一下 OnVisualParentChanged 方法自 UIElement :此方法在附加可视对象和分离时调用。这可能是处理非托管对象(套接字、文件等)的正确位置。

        3
  •  6
  •   Brian Mains    12 年前

    我也在寻找这个,在测试了不同的选择之后,我实施了威尼斯的解决方案。

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

    我意识到当父母打电话给我时 Children.Clear() 方法和已将项添加到子级,DependencyObject具有值。但当家长添加项目时( Children.Add(CustomControl) )子级为空,DependencyObject为空。

        4
  •  0
  •   Pete OHanlon    15 年前

    虽然其他人已经为您提供了关于这个问题的真正有用的信息,但您可能没有一些信息,这将解释为什么没有可识别的信息。基本上,wpf(和silverlight)大量使用weakreferences——这允许您引用gc仍然可以收集的对象。