问题 我什么时候可以处理IDisposable WPF控件,例如WindowsFormsHost?


WPF控件WindowsFormsHost继承自IDisposable。

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


12931
2017-10-31 17:18


起源

当你说'关机期间'你的意思是应用程序正在关闭?控件不再可见?对话框正在关闭? - Todd White
这里我的意思是应用程序关闭,但我也对对话框关闭案例感兴趣。 - morechilli


答案:


在应用程序关闭的情况下,您无需执行任何操作来正确处理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派生自定义类并在不同情况下进行游戏。在处理中设置一个断点并查看它何时被调用。

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

8
2017-11-02 23:44



Thx听起来不错。所以对于使用app的windowsformshost控件。生命周期我可以依赖hwdhost挂钩到调度程序关闭事件,对于一个对话框,我可以在我的控件中写一个类似的钩子来对话窗口的onclosed事件,我可以复制这两个模式的通用IDisposable控件。 - morechilli


根据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();
                    };
                }
            };

            ...

        }

        ...
    }

4
2017-11-03 12:26



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


WPF控件不实现IDisposable接口,因为 他们没有什么可以处理的 (没有清理句柄,没有非托管内存可以释放)。您需要做的就是确保您没有对控件的任何引用,GC将清除它们。

因此WPF雇佣了 弱事件模式 确保控件可以被垃圾收集。这是您需要实现的模式,以确保清理,而不是IDisposable。


0
2017-11-03 23:30



通常你是正确的 - 但是有例外 - 作为一个例子,WindowsFormsHost是一个WPF控件并且实现了IDisposable。它有一个hwnd可以处理,因为它托管winforms控件。 - morechilli
如果你有东西需要处理然后实现IDisposable,如果你没有那么。但是在你这样做之前不要实现它。 - Pop Catalin
似乎弱事件模式在您交换现有控件并希望确保该旧控件上的所有事件都被取消挂起以便它们停止处理事件的情况下仍会出现问题。在我们的实验中,似乎这些事件继续发生。调用Dispose用于在WinForms中提供此事件清理目的。 - jpierson


关闭表单时不需要处理控件,如果控件位于表单的可视树中(作为表单的子表单或表单中的其他控件),API将自动为您执行操作


-1
2017-11-01 00:42



我的WFH是包含主要wpf窗口的树中另一个WPF控件的子代。永远不会调用WFH。 - morechilli
在主wpf窗口上调用Dispose时,将处理其所有子项(等等)。您的WFH控制应在当时处理,而无需您做任何额外的工作。 - Sean Reilly
鉴于wpf应用程序类和wpf窗口类都没有从IDisposable继承似乎不太可能 - 我相信wpf不需要处理直到你拉入winforms。 - morechilli