我试图找到一种清理自定义控件可能生成的非托管资源的好方法。该场景是父窗口打开一个子窗口,该窗口具有带有非托管资源的自定义控件(请参阅下面的代码)。当CustomControl不再使用时,即当它所在的树被卸载(即子窗口关闭),或者从树中移除它(即它本身被卸载)时,需要清理这些资源
方法1:卸载事件 当您手动关闭子窗口时会触发此操作,但如果关闭父窗口(然后自动关闭子窗口)则不会触发此窗口
方法2:OnVisualChildrenChanged 子窗口由父级手动关闭或自动关闭时,不会调用此方法,仅在CustomControl移动到其他父元素时才会使用。
方法3:Dispatcher.ShutdownStarted 这并没有多大帮助,因为用户在完成应用程序之前可能已经打开/关闭了几个子窗口,并且只在最后清理了那些内存并不够好。
方法4:让CustomControl订阅ChildWindow.Closing 这也不够好......控件不应该知道它在窗口中。
方法5:终结器 遇到与方法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();
}
}
答案 0 :(得分:2)
在WPF应用程序中执行此操作的正确方法是使用MVVM模式并从View(控件)和ViewModel中删除所有逻辑和依赖项。
您的父ViewModel将创建一个实现IDisposable
的子ViewModel,然后当它删除子ViewModel时,它将在子ViewModel上调用Dispose
。
如果您的主ViewModel具有需要清理的非托管资源,那么它应该实现IDisposable
并且创建它的引导程序应该负责清理它们。
另一个好的参考是Caliburn.Micro
答案 1 :(得分: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事件。让窗口完成工作。