自动调用 Silverlight 行为的 OnDetaching()
我在 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....
}
I am using several Blend behaviors and triggers on a silverlight control. I am wondering if there is any mechanism for automatically detaching or ensuring that OnDetaching() is called for a behavior or trigger when the control is no longer being used (i.e. removed from the visual tree).
My problem is that there is a managed memory leak with the control because of one of the behaviors. The behavior subscribes to an event on some long-lived object in the OnAttached() override and should be unsubscribing from that event in the OnDetaching() override so that it can become a candidate for garbage collection. However, OnDetaching() never seems to be getting called when I remove the control from the visual tree... the only way I can get it to happen is by explicitly detaching the problematic behaviors BEFORE removing the control and then it is properly garbage collected.
Right now my only solution was to create a public method in the code-behind for the control that can go through and detach any known behaviors that would cause garbage collection problems. It would be up to the client code to know to call this before removing the control from the panel. I don't really like this approach, so I am looking for some automatic way of doing this that I am overlooking or a better suggestion.
public void DetachBehaviors()
{
foreach (var behavior in Interaction.GetBehaviors(this.LayoutRoot))
{
behavior.Detach();
}
//continue detaching all known problematic behaviors on the control....
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在这种情况下,您真正需要的不是某种自动分离的方法,而是确保长期存在的对象所持有的引用不会阻止该行为(以及它所引用的其他所有内容)被垃圾收集。
这是通过实现中介者模式来实现的。这个概念是,您不会为长期存在的对象提供一个引用您的
Behaviour
的委托,而是创建一个 Mediator 类作为中间人。中介器附加到长期存在的对象事件并保存 对行为的弱引用。当长期存在的对象触发事件时,中介器会检查弱引用是否仍然存在,如果存在则调用其上的方法来传递事件。如果事件发生时,中介发现WeakReference
不再活动,它将其事件处理程序与长期存在的对象分离。因此,没有什么可以阻止这种行为,并且涉及到被垃圾收集的所有其他内容,剩下的只是一个非常小的中介实例,其死引用仍然附加到长期存在的对象上。由于这些调解者很小,它们并不代表真正的问题,甚至这些调解者也会在下次事件触发时消失。
幸运的是,您不必自己构建这些东西,其他人已经完成了。它称为
WeakEventListener
。此博客: 突出显示“弱”贡献;增强功能使使用 WeakEventListener 防止内存泄漏变得更加容易! 有一组关于该主题的优秀链接。What you really need in this case is not some way to automatically detach but to ensure that the reference held by the long lived object does not keep the behaviour (and therefore everything else it has a reference to) from being garbage collected.
This is acheived by implementing a Mediator pattern. The concept is that you don't give the long-lived object a delegate with a reference to your
Behaviour
, instead you create a Mediator class as a go-between. The mediator attaches to the long-lived objects event and holds a WeakReference to the behaviour. When the long-lived object fires the event the mediator checks that theWeakReference
is still alive, if so calls a method on it to pass on the event. If when the event occurs the mediator finds that theWeakReference
is no longer alive it detaches its event handler from the long lived object.Hence there is nothing stopping the behaviour and everything else involved from being garbage collected all thats left is a very small mediator instance with a dead reference still attached to the long-lived object. Since these mediators are tiny they don't represent a real problem and even those will disappear the next time the event fires.
Fortunately you don't have to build this stuff yourself others have already done it. It is called the
WeakEventListener
. This blog: Highlighting a "weak" contribution; Enhancements make preventing memory leaks with WeakEventListener even easier! has an excellent set of links on the subject.Joost van Schaik 提供了另一种清洁方式从附加行为中引用,同时避免内存泄漏问题。它取决于使用 AssociatedObject 的 Loaded 和 Unloaded 事件的委托来完成清理工作。
他还提供了一个代码片段,用于为附加行为生成存根。
Joost van Schaik offers an alternative way to clean up references from attached behaviors, while avoiding the problem with the memory leak. It depends on doing the cleanup work using delegates of the Loaded and Unloaded events of the AssociatedObject.
He also offers a code-snippet for generating stubs for attached behaviors.