【问题标题】:ListBox virtualization not unloading items [duplicate]ListBox虚拟化不卸载项目[重复]
【发布时间】:2017-12-14 09:24:54
【问题描述】:

我在列表框中加载了很多图像。 在我尝试虚拟化之前有一段合理的加载时间。

现在我使用虚拟化,只加载视图中的元素,完全符合我的要求; 但是一旦它们落在视图之外,它们似乎就不会卸载,所以如果我一直向下滚动到底部,所有项目都已加载,我将失去虚拟化的优势。

在我显示任何图像之前,我的应用程序消耗 140MB,然后我显示 10 张图像,我的内存使用量等于 161MB,如果我滚动到最后一张图像,使用量是 300MB。如果 10 张图片使用 21 MB,则必须加载 300MB 的所有图片。

通过使用 Snoop 检查加载的 ListBoxItems 的数量,进一步确认了此行为。

代码中没有什么特别之处,我只是确保CanContentScrollenable 是正确的,而不是禁用虚拟化。我自定义了ItemContainerStyleListBox 的模板,但它不应该影响虚拟化(或者至少不仅仅是卸载部分),不是吗?

<ListBox ItemsSource="{Binding myItems}"  CanContentScroll="True"/>

我错过了什么吗?

结论

虚拟化显然有效。当每个 ItemContainer 落在视图之外时,它们都会在某个时刻被卸载。

问题可能是 BitmapImage 是如何缓存的。事实上,我正在使用以下 DataTemplate 来显示图像:

 <Image>
     <Image.Source>
         <BitmapImage UriSource="{Binding}" />
     </Image.Source>
 </Image>

【问题讨论】:

  • “他们似乎没有卸载”中,“似乎”这个词表明你正在以某种方式感知某些东西,这您解释为他们没有“卸载”。您能否更具体一点,以及您所说的“卸载”是什么意思?您只是在谈论Unloaded 事件吗?
  • CanContentScroll 启用虚拟化? &lt;ListView VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling"/&gt;呢?
  • @EdPlunkett 当然:在我显示任何图像之前,我的应用程序消耗 140MB,然后我显示 10 张图像,我的内存使用量等于 161MB,如果我滚动到最后一张图像,使用量是 300MB。如果 10 张图片使用 21 MB,则必须加载 300MB 的所有图片。
  • @sam 谢谢。这将是对问题的一个很好的补充。
  • @sam 除了内存消耗,你如何检测项目容器没有被卸载?您是否附加了 Unloaded 事件处理程序?

标签: wpf listbox virtualization


【解决方案1】:

这里发生的是BitmapImageStream 的内存泄漏问题。 问题描述here

解决方案是通过WrappingStream 读取图像,如描述和实现here

像这样读取图像并将其分配给Image.Source

  BitmapImage bitmap = new BitmapImage();

  using( var stream = new FileStream( uri, FileMode.Open ) )
  using( WrappingStream wrapper = new WrappingStream( stream ) )
  {
      bitmap.BeginInit();
      bitmap.CacheOption = BitmapCacheOption.OnLoad;
      bitmap.StreamSource = stream;
      bitmap.EndInit();
      bitmap.Freeze();
 }

  return bitmap;

【讨论】:

  • 好收获。我不知道 FileStream 也会发生这种情况。
猜你喜欢
  • 2010-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-28
相关资源
最近更新 更多