为啥 UserControl 的 Unloaded 事件不会触发?

Posted

技术标签:

【中文标题】为啥 UserControl 的 Unloaded 事件不会触发?【英文标题】:Why the Unloaded event of UserControl would not fire?为什么 UserControl 的 Unloaded 事件不会触发? 【发布时间】:2017-05-22 03:48:04 【问题描述】:

我刚刚在我正在开发的一个简单的 Windows 应用商店应用中发现了一个巨大的内存泄漏。

原来我在 ListView 的ItemTemplate 中放置了一个 UserControl,并挂钩了 UserControl 的Unloaded 事件以分离一些事件处理程序。

我预计当 ListView 的项目被清除时,UserControl 的Unloaded 事件会触发,但它不会!但是当我删除一项一项时,UserControl 的Unloaded 事件将按预期触发。

有人可以给我一些建议吗?或者除了挂钩Unloaded 事件之外,我应该把清理代码放在哪里。任何想法将不胜感激!谢谢!下面是代码sn-p:

为了简化,ListView的ItemTemplate是:

 <DataTemplate>
      <local:MyUserControl1 />
 </DataTemplate>

而 MyUserControl1 只是一个空的 UserControl:

public sealed partial class MyUserControl1 : UserControl

    public MyUserControl1()
    
        this.InitializeComponent();
        this.Unloaded += MyUserControl1_Unloaded;
    

    private void MyUserControl1_Unloaded(object sender, RoutedEventArgs e)
    
        Debug.WriteLine("MyUserControl1_Unloaded...");
    

【问题讨论】:

【参考方案1】:

默认的 ListView 会启用 UI 虚拟化。当你调用Clear() 方法时,ListView 会做一些特殊处理,它实际上并没有删除这些项目(相信你也发现了这种情况)。

您可以在实时可视化树中看到 ListView 的 ActualHeight(设置为 0)。这就是你在 UI 上看不到 listview 的原因。

所以解决方法是使用Remove() 方法或listview.Itemsource=null。您也可以尝试禁用 UI 虚拟化。例如,使用 StackPanel 作为 ItemsPanelTemplate。

【讨论】:

是的,你是对的。它是 ListView ui 虚拟化的设计机制。我将继续使用 ui 虚拟化,并找到了控制缓存大小的解决方案。这是我在 msdn 上的帖子:social.msdn.microsoft.com/Forums/en-US/… 问题依然存在。我已经尝试了这两种方法:1)一个一个地删除所有项目(而不是清除);2)让 listview.Itemsource = null。 ListView 还保留了一些项目,我希望所有项目都从内存中删除。 @SimonFisher 我参考您的 MSDN 线程上的代码进行测试。我无法重现此问题。当我调用Clear(),Remove() 方法时,这些项目将被删除。我在 SnapShot 报告中找不到它。 我再次运行性能分析器几次,每次都得到相同的结果:内存中将保留 75 或 76 个项目(我已单击强制 GC)。仍在寻找原因。

以上是关于为啥 UserControl 的 Unloaded 事件不会触发?的主要内容,如果未能解决你的问题,请参考以下文章

处理 WPF 用户控件

为啥在 UserControl 中没有正确更新 Visible 属性?

为啥我不能在我的 UserControl 中重置 TextBox 的背景?

为啥我不能在同一个程序集中使用 UserControl 上的 Name 属性?

处置WPF用户控件

为啥在数据模板中使用 xaml UserControl 时无法绑定到依赖属性? [复制]