WPF内置控件如何管理它们的事件处理程序以便附加到事件?

5
我知道当你将一个对象注册到鼠标的附加事件时,会出现内存泄漏。这就是为什么你需要使用“弱事件模式”的原因。(点击此处查看) 但我有一个问题:如果你想使用它,就不能在XAML代码中定义处理程序。
对我来说,这意味着每个像这样的代码都会出现内存泄漏:
<SomeControl Mouse.MouseDown="MyHandler" />

除非您在代码中明确删除处理程序(我怀疑任何人都不会这样做)。现在有一些事情我不理解:
<Button Click="MyHandler" />

这段代码在某个地方使用了Mouse.MouseDown事件来检测按钮的点击。 通过使用反编译工具Reflector,我发现该事件使用了UIElement类的MouseDown。当我读取UIElement的代码时,我不理解:它没有WeakEventManager!

有人能解释一下UIElement如何接收来自Mouse.MouseDown的事件而不泄漏吗?

1个回答

7

XAML中使用普通的处理程序不需要弱引用。

您正在创建一个内存引用,将主控件与此控件中包含的子控件(在此示例中是按钮)连接起来;子控件是指按钮。

如果有人维护对主控件的可视树的任何部分的引用,则整个树将保留在内存中,因为它们通过父/子引用链接在一起。

现在,如果删除了对该树的所有引用,则父控件和子控件之间的事件引用(主控件和按钮之间)并不重要,因为这些控件已经通过父/子引用链接在一起。一旦删除了所有外部引用,该控件就可以进行垃圾回收。

XAML中的事件处理程序仅创建内部事件引用。

当外部客户端在控件上注册事件时,必须小心,因为这会创建一个外部引用,只要链接和客户端存在(除非它是一个弱引用),就会使控件保持活动状态。

您的问题涉及附加事件。目前似乎没有任何明确的文档说明附加事件是否会导致内存泄漏。在我的看法中,订阅事件的UI控件包含对事件的引用,而不是相反,但我认为静态事件对象必须有一种通知控件已被触发的方式。从微软方面似乎没有太多关于此的评论。


我同意你的观点,然而在XAML中,对于附加事件的处理程序(我指的不是控件的事件,而是像Mouse.MouseDown这样的事件)可能会造成内存泄漏,因为它总是有一个引用。 在内部,Button类使用了Mouse.MouseDown事件(具体来说是UIElement)。但我不知道为什么这个没有造成内存泄漏。 - Nicolas Dorier

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接