【问题标题】:When can I dispose an IDisposable WPF control e.g. WindowsFormsHost?我什么时候可以处理 IDisposable WPF 控件,例如Windows 窗体主机?
【发布时间】:2008-10-31 17:18:46
【问题描述】:

WPF 控件 WindowsFormsHost 继承自 IDisposable。

如果我有一个包含上述某些控件的复杂 WPF 可视化树,我可以在关机期间使用什么事件或方法来调用 IDispose?

【问题讨论】:

  • 当您说“关闭期间”时,您的意思是应用程序正在关闭吗?控件不再可见?正在关闭对话框?
  • 这里我的意思是应用程序关闭,但我也对对话框关闭案例感兴趣。

标签: c# .net wpf idisposable


【解决方案1】:

在应用程序关闭的情况下,您无需执行任何操作即可正确处理 WindowsFormsHost。因为它派生自 HwndHost,所以在 Dispatcher 关闭时处理。如果你使用 Reflector,你会看到当 HwndHost 被初始化时,它会创建一个 WeakEventDispatcherShutdown。

如果您在对话框中使用它,我可以建议的最好方法是覆盖 OnClosed 并随后处置您的主机,否则 HwndHost 将一直挂起,直到 Dispatcher 关闭。

public partial class Dialog : Window
{
    public Dialog()
    {
        InitializeComponent();
    }

    protected override void OnClosed(EventArgs e)
    {
        if (host != null)
            host.Dispose();

        base.OnClosed(e);
    }
}

测试何时调用 dispose 的一种简单方法是从 WindowsFormsHost 派生一个自定义类并尝试不同的情况。在 dispose 中设置一个断点,看看它什么时候被调用。

public class CustomWindowsFormsHost : WindowsFormsHost
{
    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);
    }
}

【讨论】:

  • Thx 听起来不错。所以对于带有应用程序的 windowsformshost 控件。我可以依靠 hwdhost 挂钩到调度程序关闭事件,对于一个对话框,我可以在我的控件中编写一个与对话框窗口的 onclose 事件类似的挂钩,并且我可以将这两种模式复制到一个通用的 IDisposable 控件。
【解决方案2】:

根据 Todd 的回答,我为任何由 Window 托管的 WPF 控件提出了这个通用解决方案,并希望在该窗口关闭时保证处置。

(显然如果你可以避免从 IDisposable 继承,但有时你不能)

当层次结构中的第一个父窗口关闭时调用Dispose。

(可能的改进 - 将事件处理更改为使用弱模式)

public partial class MyCustomControl : IDisposable
    {

        public MyCustomControl() {
            InitializeComponent();

            Loaded += delegate(object sender, RoutedEventArgs e) {
                System.Windows.Window parent_window = Window.GetWindow(this);
                if (parent_window != null) {
                    parent_window.Closed += delegate(object sender2, EventArgs e2) {
                        Dispose();
                    };
                }
            };

            ...

        }

        ...
    }

【讨论】:

  • 问题:你在dispose方法中做了什么?
  • 取决于控件-通常您没有任何东西,但不幸的是,有些特殊情况请参阅我对您的回答的评论
  • 对于那些在 Windows 窗体应用程序中托管 WPF 的人来说,这将失败。有更多兼容的方法也可以选择连接到主窗体的关联 WinForms 关闭事件,但正如您所拥有的那样,这对于广泛可重用的 WPF 控件库来说是不够的。此外,仅在主窗口关闭时进行清理可能并不是大多数开发人员想要的。相反,当树上的第一个窗口/页面超出范围时(不一定在关闭时)进行清理可能更可取。
  • 谢谢 - 听起来你有一些有用的想法 - 如果你想提交一个描述更好和更通用解决方案的答案,那么我很乐意取消选择这个答案并考虑你的。
【解决方案3】:

你不需要在关闭窗体时释放控件,如果控件在窗体的可视化树中(作为窗体的子级或窗体中的其他控件),API 会自动为你完成

【讨论】:

  • 我的 WFH 是包含主 wpf 窗口的树中另一个 WPF 控件的子项。永远不会调用 WFH 上的 Dispose。
  • 当在 wpf 主窗口调用 Dispose 时,它​​的所有子窗口都将被释放(以此类推)。您的 WFH 控件应该在那时被处理掉,而无需您做任何额外的工作。
  • 鉴于 wpf 应用程序类和 wpf 窗口类都不是从 IDisposable 继承的,这似乎不太可能 - 我相信 wpf 在您拉入 winforms 之前无需进行处置。
【解决方案4】:

WPF 控件不实现 IDisposable 接口,因为它们没有要处理的东西(没有要清理的句柄,没有要释放的非托管内存)。您需要做的就是确保您没有对控件的任何引用,并且 GC 会清理它们。

因此 WPF 使用 weak event patterns 来确保控件可以被垃圾回收。这是您需要实施以确保清理的模式,而不是 IDisposable。

【讨论】:

  • 通常你是正确的 - 但也有例外 - 例如 WindowsFormsHost 是一个 WPF 控件并且确实实现了 IDisposable。它确实有一个 hwnd 需要处理,因为它承载了 winforms 控件。
  • 如果你有东西要处理,那么实现 IDisposable,如果你没有,那就不要。但是在你做之前不要去实现它。
  • 在您更换现有控件并希望确保该旧控件上并由该控件处理的所有事件都被取消挂钩的情况下,弱事件模式似乎仍然会造成问题,因此他们停止处理事件。在我们的实验中,这些事件似乎继续发生。调用 Dispose 在 WinForms 中也用于此事件清理目的。
猜你喜欢
  • 1970-01-01
  • 2011-10-10
  • 2010-12-27
  • 2011-12-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多