我在 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....
}
有帮助吗?

解决方案

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

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

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

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

其他提示

乔斯特·范·沙克(Joost van Schaik) 提供另一种方法来清理附加行为的参考,同时避免记忆泄漏的问题。这取决于使用关联对象的已加载和卸载事件的代表进行清理工作。

他还提供了用于生成用于附加行为的存根的代码刺。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top