5

我在 silverlight 控件上使用了几种混合行为和触发器。我想知道是否有任何机制可以自动分离或确保在不再使用控件时(即从可视树中删除)为行为或触发器调用 OnDetaching()。

我的问题是由于其中一种行为,控件存在托管内存泄漏。该行为订阅 OnAttached() 覆盖中某个长期存在的对象上的事件,并且应该在 OnDetaching() 覆盖中取消订阅该事件,以便它可以成为垃圾回收的候选对象。但是,当我从可视化树中删除控件时,似乎永远不会调用 OnDetaching() ......我可以让它发生的唯一方法是在删除控件之前显式分离有问题的行为,然后正确地收集垃圾.

现在我唯一的解决方案是在代码隐藏中为控件创建一个公共方法,该方法可以通过并分离任何会导致垃圾收集问题的已知行为。在从面板中删除控件之前,由客户端代码知道调用它。我真的不喜欢这种方法,所以我正在寻找一些我忽略的自动方法或更好的建议。

public void DetachBehaviors()
{
     foreach (var behavior in Interaction.GetBehaviors(this.LayoutRoot))
     {
          behavior.Detach();
     }

     //continue detaching all known problematic behaviors on the control....
}
4

2 回答 2

3

在这种情况下,您真正​​需要的不是某种自动分离的方法,而是确保长寿命对象持有的引用不会阻止行为(以及它引用的所有其他内容)被垃圾收集。

这是通过实现中介者模式来实现的。这个概念是你不要给长寿命对象一个引用你的委托Behaviour,而是创建一个 Mediator 类作为中间人。中介附加到长寿命对象事件并持有对该行为的弱引用。当长寿命对象触发事件时,中介器检查它WeakReference是否还活着,如果是,则调用它的方法来传递事件。如果当事件发生时,调解器发现它WeakReference不再活动,它会将其事件处理程序从长期存在的对象中分离出来。

因此,没有什么可以阻止这种行为,并且被垃圾收集所涉及的所有其他事情都是一个非常小的中介实例,其中一个死引用仍然附加到长生命周期的对象。由于这些调解器很小,它们并不代表真正的问题,甚至在下次事件触发时它们也会消失。

幸运的是,您不必自己构建这些东西,其他人已经完成了。它被称为WeakEventListener. 这个博客: 突出一个“弱”的贡献;增强功能使使用 Wea​​kEventListener 防止内存泄漏变得更加容易!在该主题上有一组出色的链接。

于 2010-04-23T07:16:01.357 回答
3

Joost van Schaik提供了一种替代方法来清除附加行为中的引用,同时避免内存泄漏问题。它依赖于使用 AssociatedObject 的 Loaded 和 Unloaded 事件的委托进行清理工作。

他还提供了一个代码片段,用于为附加行为生成存根。

于 2012-02-28T11:09:05.480 回答