1

我正在尝试找到一种清理自定义控件可能生成的非托管资源的好方法。该场景是父窗口打开一个子窗口,该子窗口具有带有非托管资源的自定义控件(请参见下面的代码)。当 CustomControl 不再使用时,即当它所在的树被卸载(即子窗口关闭)或从树中移除(即它本身被卸载)时,需要清理这些资源

方法1:卸载事件 当您手动关闭子窗口时触发,但如果您关闭父窗口(然后自动关闭子窗口)则不会触发

方法 2:OnVisualChildrenChanged 当子窗口手动或由父级自动关闭时不会调用此方法,并且仅在将 CustomControl 移动到不同的父元素时使用。

方法 3:Dispatcher.ShutdownStarted 这并没有太大帮助,因为用户可能在完成应用程序之前已经打开/关闭了几个子窗口,并且仅在最后清理内存还不够好。

方法 4:让 CustomControl 订阅 ChildWindow.Closing 这也不够好,.. 控件不必知道它在窗口中。

方法 5:Finalizer 遇到与方法 3 相同的问题,.. 可能需要一段时间才能调用它

public class CustomControlWithManagedResources : Control
{
    ~CustomControlWithManagedResources()
    {
        Console.WriteLine("~CustomControlWithManagedResources");
    }

    public CustomControlWithManagedResources()
    {
        Unloaded += CustomControl_Unloaded;
        Dispatcher.ShutdownStarted += Dispatcher_ShutdownStarted;
    }

    void Dispatcher_ShutdownStarted(object sender, EventArgs e)
    {
        Console.WriteLine("ShutdownStarted");
    }

    void CustomControl_Unloaded(object sender, RoutedEventArgs e)
    {
        Console.WriteLine("Unloaded");
    }

    protected override void OnVisualParentChanged(DependencyObject oldParent)
    {
        base.OnVisualParentChanged(oldParent);

        if(oldParent != null)
            Console.WriteLine("OnVisualParentChanged");
    }
}

public class ChildWindow : Window
{
    public ChildWindow()
    {
        Content = new CustomControlWithManagedResources();
    }
}

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

    protected override void OnMouseDoubleClick(MouseButtonEventArgs e)
    {
        base.OnMouseDoubleClick(e);
        new ChildWindow() { Owner = this }.Show();
    }
}
4

2 回答 2

2

在 WPF 应用程序中执行此操作的正确方法是使用MVVM模式,并从您的视图(控件)和 ViewModel 中删除所有逻辑和依赖项。

您的父 ViewModel 将创建一个已实现的子 ViewModel,IDisposable然后当它删除子 ViewModel 时,它将调用Dispose子 ViewModel。

如果您的主 ViewModel 有需要清理的非托管资源,那么它应该实现IDisposable并且创建它的引导程序应该负责清理它们。

另一个很好的参考是Caliburn.Micro

于 2014-04-21T15:44:12.937 回答
1

您似乎在要求关闭事件。

看看这个:

http://msdn.microsoft.com/en-us/library/system.windows.window_events(v=vs.110).aspx

当一个窗口关闭时,它会引发两个事件:Closing 和 Closed。

虽然可以通过非客户区和客户区提供的机制显式关闭窗口,但也可以由于应用程序或 Windows 的其他部分的行为而隐式关闭窗口,包括以下内容:

用户注销或关闭 Windows。

窗口的所有者关闭(请参阅所有者)。

主应用程序窗口关闭且 ShutdownMode 为 OnMainWindowClose。

称为关机。

在所有这些场景中,将调用 Closing 和 Close 事件。

不要为您的控件订阅 Window.Closing 事件。让窗口完成这项工作。

于 2014-04-21T09:35:43.763 回答