释放 WPF 用户控件

我已经创建了一个自定义的 WPF 用户控件,它将被第三方使用。我的控件有一个可抛弃的私有成员,我想确保一旦包含窗口/应用程序关闭,它的释放方法总是被调用。但是,UserControl 不是一次性的。

我尝试实现 IDisposable 接口并订阅 Unload 事件,但是在主机应用程序关闭时都没有被调用。MSDN 表示可能根本不会引发卸载事件。它也可能被触发不止一次,也就是用户更改主题的时候。

如果可能的话,我不希望依赖于控件的使用者记得调用特定的 Dispose 方法。

 public partial class MyWpfControl : UserControl
{
SomeDisposableObject x;


// where does this code go?
void Somewhere()
{
if (x != null)
{
x.Dispose();
x = null;
}


}
}

到目前为止,我找到的唯一解决方案是订阅 Dispatcher 的 ShutdownStarted 事件。这样合理吗?

this.Dispatcher.ShutdownStarted += Dispatcher_ShutdownStarted;
114200 次浏览

有趣的博客文章: 释放 WPF 用户控件(略)

它提到订阅 调度员,已关闭来处理您的资源。

UserControl 有一个析构函数,为什么不使用它呢?

~MyWpfControl()
{
// Dispose of any Disposable items here
}

使用析构函数时要小心。这将在 GC Finalizer 线程上调用。在某些情况下,您释放的资源可能不喜欢在与创建它们的线程不同的线程上释放。

我的场景几乎没有什么不同,但是我想知道的意图是相同的,当父窗口托管我的用户控件是关闭/关闭的视图(即我的用户控件)应该调用显示器 oncloseView 来执行一些功能和执行清理。(我们正在 WPF PRISM 应用程序上实现一个 MVP 模式)。

我刚刚发现,在用户控件的 Loadedevent 中,我可以将 ParentWindowCclose 方法连接到 Parent Windows Cclose 事件。这样,我的用户控件就可以知道父窗口何时关闭,并相应地采取行动!

Dispatcher.ShutdownStarted事件仅在应用程序结束时触发。值得在控件停止使用时调用处理逻辑。特别是在应用程序运行时多次使用控件时,它释放资源。因此,IWint的解决方案更可取。密码是这样的:

public MyWpfControl()
{
InitializeComponent();
Loaded += (s, e) => { // only at this point the control is ready
Window.GetWindow(this) // get the parent window
.Closing += (s1, e1) => Somewhere(); //disposing logic here
};
}

我使用以下交互行为向 WPF 用户控件提供卸载事件。 您可以在 UserControls XAML 中包含该行为。 因此,您可以拥有这些功能,而无需将其放置在每个 UserControl 中的逻辑中。

XAML 声明:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"


<i:Interaction.Behaviors>
<behaviors:UserControlSupportsUnloadingEventBehavior UserControlClosing="UserControlClosingHandler" />
</i:Interaction.Behaviors>

代码背后处理程序:

private void UserControlClosingHandler(object sender, EventArgs e)
{
// to unloading stuff here
}

行为准则:

/// <summary>
/// This behavior raises an event when the containing window of a <see cref="UserControl"/> is closing.
/// </summary>
public class UserControlSupportsUnloadingEventBehavior : System.Windows.Interactivity.Behavior<UserControl>
{
protected override void OnAttached()
{
AssociatedObject.Loaded += UserControlLoadedHandler;
}


protected override void OnDetaching()
{
AssociatedObject.Loaded -= UserControlLoadedHandler;
var window = Window.GetWindow(AssociatedObject);
if (window != null)
window.Closing -= WindowClosingHandler;
}


/// <summary>
/// Registers to the containing windows Closing event when the UserControl is loaded.
/// </summary>
private void UserControlLoadedHandler(object sender, RoutedEventArgs e)
{
var window = Window.GetWindow(AssociatedObject);
if (window == null)
throw new Exception(
"The UserControl {0} is not contained within a Window. The UserControlSupportsUnloadingEventBehavior cannot be used."
.FormatWith(AssociatedObject.GetType().Name));


window.Closing += WindowClosingHandler;
}


/// <summary>
/// The containing window is closing, raise the UserControlClosing event.
/// </summary>
private void WindowClosingHandler(object sender, CancelEventArgs e)
{
OnUserControlClosing();
}


/// <summary>
/// This event will be raised when the containing window of the associated <see cref="UserControl"/> is closing.
/// </summary>
public event EventHandler UserControlClosing;


protected virtual void OnUserControlClosing()
{
var handler = UserControlClosing;
if (handler != null)
handler(this, EventArgs.Empty);
}
}

我觉得4.7版的“卸载”应该叫做“硬存在”。但是,如果你玩的是老版本的。Net,尝试在加载方法中这样做:

e.Handled = true;

我不认为旧版本将卸载,直到加载处理。只是因为我看到其他人还在问这个问题,并没有看到这个提议作为一个解决方案。我只碰。网一年几次,并遇到这几年回来。但是,我想知道它是否像卸载完成之前不调用卸载那样简单。看起来对我有用,但是对新人来说。Net 似乎总是调用 unload,即使加载没有标记为已处理。