当事件附加到UserControl上时,它不会被销毁

本文关键字:上时 事件 UserControl | 更新日期: 2023-09-27 18:14:06

我在usercontrol中有以下代码行:

Application.Current.RootVisual.MouseLeftButtonDown += RootClicked;

当它被定义父用户控件不再被GC收集或销毁时,RootClicked事件继续触发,即使它不再活动。

如果我添加:

Application.Current.RootVisual.MouseLeftButtonDown -= RootClicked;

问题已解决。

知道这是为什么吗?是否有一个函数我应该明确地删除事件?

当事件附加到UserControl上时,它不会被销毁

这是一种正常的行为,也是。net中内存泄漏的常见来源。

当您将对象A的实例方法附加到对象B的事件时,您将在事件接收者列表中添加A的实例,因此垃圾收集器无法释放对象A,直到您删除处理程序或释放对对象A和B的每个引用。

有两种常见的方法来解决这个问题:

1)当您不再需要对象A时,从事件中取消订阅对象A。

2)使用弱事件,就像WPF一样。弱事件通常是通过WeakReference类实现的,你可以在web上找到更多的信息。

结果:mouseleftbuttondown事件在其调用列表中保持对控件的引用,因此控件不符合收集条件(因为它是由委托引用的)。

解决方案:

在订阅MouseLeftButtonDown事件后订阅Unloaded事件,并在Unloaded事件处理程序中取消订阅MouseLeftButtonDown事件:

 ...
 Application.Current.RootVisual.MouseLeftButtonDown += RootVisual_MouseLeftButtonDown;
 this.Unloaded += Control_Unloaded;
 ...
 void Control_Unloaded(object sender, RoutedEventArgs e)
 {
    Application.Current.RootVisual.MouseLeftButtonDown -= RootVisual_MouseLeftButtonDown;
 }

或者更简洁:

Application.Current.RootVisual.MouseLeftButtonDown += RootVisual_MouseLeftButtonDown;
this.Unloaded += (s, e) => Application.Current.RootVisual.MouseLeftButtonDown -= RootVisual_MouseLeftButtonDown;

这是一种已知的行为,但大多数开发人员都没有意识到这一点。您应该查看弱事件模式,了解如何以一种比手动删除事件处理程序更优雅(如果编码更密集)的方式绕过此限制。