正确清理 WPF 用户控件控件、正确、用户、WPF

2023-09-07 15:05:10 作者:你大可不必假惺惺

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

I am relatively new to WPF, and some things with it are quite foreign to me. For one, unlike Windows Forms, the WPF control hierarchy does not support IDisposable. In Windows Forms, if a user control used any managed resources, it was very easy to clean up the resources by overriding the Dispose method that every control implemented.

在 WPF 中,事情并没有那么简单.找了好几个小时,遇到了两个基本的主题:

In WPF, the story is not that simple. I have searched for this for several hours, and encountered two basic themes:

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

The first theme is Microsoft clearly stating that WPF does not implement IDisposable because the WPF controls have no unmanaged resources. While that may be true, they seem to have completely missed the fact that user extensions to their WPF class hierarchy may indeed use managed resources (directly or indirectly through a model). By not implementing IDisposable, Microsoft has effectively removed the only guaranteed mechanism by which unmanaged resources used by a custom WPF control or window can be cleaned up.

其次,我发现了一些对 Dispatcher.ShutdownStarted 的引用.我曾尝试使用 ShutdownStarted 事件,但它似乎并没有为每个控件触发.我有一堆 WPF UserControl,我已经为 ShutdownStarted 实现了一个处理程序,并且它永远不会被调用.我不确定它是否仅适用于 Windows,或者 WPF App 类.但是它没有正确触发,每次应用程序关闭时我都会泄漏打开的 PerformanceCounter 对象.

Second, I found a few references to Dispatcher.ShutdownStarted. I have tried to use the ShutdownStarted event, but it does not seem to fire for every control. I have a bunch of WPF UserControl's that I have implemented a handler for ShutdownStarted, and it never gets called. I am not sure if it only works for Windows, or perhaps the WPF App class. However it is not properly firing, and I am leaking open PerformanceCounter objects every time the app closes.

有没有比 Dispatcher.ShutdownStarted 事件更好的方法来清理非托管资源?实现 IDisposable 是否有一些技巧可以调用 Dispose ?如果可能的话,我更愿意避免使用终结器.

Is there a better alternative to cleaning up unmanaged resources than the Dispatcher.ShutdownStarted event? Is there some trick to implementing IDisposable such that Dispose will be called? I would much prefer to avoid using a finalizer if at all possible.

推荐答案

恐怕 Dispatcher.ShutdownStarted 似乎确实是 WPF 提供的用于在 UserControls 中处理资源的唯一机制.(参见我不久前问的一个非常类似问题).

I'm afraid that Dispatcher.ShutdownStarted really does seem to be the only mechanism WPF provides for disposing of resources in UserControls. (See a very similar question I asked a while ago).

解决该问题的另一种方法是将所有可支配资源(如果可能的话)从背后的代码中移出并放入单独的类中(例如使用 MVVM 模式时的 ViewModel).然后在更高级别上,您可以处理主窗口关闭并通过 Messenger 类通知所有 ViewModel.

Another way to approach the problem is to move all of your disposable resources (if at all possible) out of the code behind and into separate classes (such as the ViewModel when using the MVVM pattern). Then at a higher level you could handle your main window closing and notify all the ViewModels via a Messenger class.

我很惊讶您没有收到 Dispatcher.ShutdownStarted 事件.您的用户控件当时是否附加到顶级窗口?

I am surprised you don't get the Dispatcher.ShutdownStarted event. Are your UserControls attached to the top-level window at the time?