我正在开发一个自定义控件,它在内部订阅了Touch.FrameReported - 一个静态事件。这有可能导致内存泄漏(在某些情况下,确实如此)。
这是我目前的解决方案。订阅/取消订阅已加载/已卸载事件。但是,我发现并不总是调用Unloaded事件。这可能导致内存泄漏。
// Imagine this is a CustomControl, to be consumed by users
// with no regard for calling Dispose
public class CustomGrid : Grid
{
public CustomGrid()
{
Loaded += (s, a) =>
{
Touch.FrameReported -= OnTouchFrameReported;
Touch.FrameReported += OnTouchFrameReported;
};
Unloaded += (s, a) =>
{
// The intention is to unsubscribe on unload, which should pre-date
// user intended 'disposal' of the control
Touch.FrameReported -= OnTouchFrameReported;
};
}
是否有一种已知的模式可以解决这个问题?取消订阅自定义控件中的事件'拆卸'?我已经尝试过了:
答案 0 :(得分:1)
tl; dr如果您使用#1(卸载时取消订阅)和#3(弱事件监听器)的组合,那么我不认为您的控件应该因任何内存泄漏而出错。你无能为力。
实施IDisposable
并没有真正帮助,因为没有人想要打电话" Dispose"在UI元素上,无论如何,在那些" Unloaded"没有被叫,要求" Dispose"只会把罐头踢到路上。而且你是对的,如果有一个静态事件作为其调用列表的一部分持有你的控件,则不会调用终结器。
我的理解是"卸载"从Visual Tree中删除控件时应该调用。所以在"卸载"没有触发它肯定应该在哪里,然后在某个框架控件中有一个错误(which does seem to be a possibility),或者你的用户有一个错误'阻止您的控件容器被卸载的代码。在任何一种情况下,您的控件都不会成为内存泄漏的来源。
使用弱事件处理程序可能是一个很好的故障保护 - 它允许您的控件成为GC,如果对它的唯一引用是弱事件侦听器(因此,这将阻止您的" FrameReported& #34;监听器导致内存泄漏)。我理解你关于实现的观点 - 实现起来似乎很棘手,但原则上这个技术没有任何问题(你可能知道,框架使用它作为绑定的事件监听器)。