我在Silverlight控件上使用了几个Blend行为和触发器。我想知道是否有任何机制可以自动分离或确保在不再使用控件(即从可视树中删除)时为行为或触发器调用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....
}
答案 0 :(得分:3)
在这种情况下你真正需要的不是某种自动分离的方法,而是确保长寿命对象持有的引用不会保持行为(因此它引用的所有其他内容)不被垃圾收集。
这是通过实现Mediator模式实现的。这个概念是,您不会为长期居住的对象提供引用Behaviour
的委托,而是创建一个Mediator类作为中间人。介体附加到长寿命对象事件并保持行为WeakReference。当长期存在的对象触发事件时,调解器会检查WeakReference
是否仍然存活,如果是,则调用其上的方法来传递事件。如果事件发生时,介体发现WeakReference
不再存在,则会将其事件处理程序与长期存在的对象分离。
因此没有什么能阻止这种行为,并且所有其他事情都被垃圾收集所剩下的所有内容都是一个非常小的中介实例,其中死引用仍然附加到长寿命对象上。由于这些调解员很小,所以它们并不代表真正的问题,甚至在下次事件发生时它们也会消失。
幸运的是,你不必自己构建这些东西,其他人已经做过了。它被称为WeakEventListener
。这篇博客:Highlighting a "weak" contribution; Enhancements make preventing memory leaks with WeakEventListener even easier!有很多关于这个主题的链接。
答案 1 :(得分:3)
Joost van Schaik提供了另一种清除附加行为引用的方法,同时避免了内存泄漏问题。它取决于使用AssociatedObject的Loaded和Unloaded事件的委托进行清理工作。
他还提供了一个代码片段,用于为附加行为生成存根。