考虑以下示例XAML文件,其中显示Facebook的前1000人,从markz开始作为第4人.请注意,这只是一个示例.任何具有1000个元素的窗口,无论您如何构建它,都是一个很好的演示.
<Window x:Class="SO.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:clr="clr-namespace:System;assembly=mscorlib"
Title="MainWindow" Height="350" Width="525">
<ListBox ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Window>
Run Code Online (Sandbox Code Playgroud)
而背后的代码:
public partial class MainWindow : Window
{
public MainWindow() {
InitializeComponent();
string[] urls = new string[1000];
for (int i = 0; i < 1000; ++i) {
urls[i] = "http://graph.facebook.com/" + i + "/picture";
}
this.DataContext = urls;
}
}
Run Code Online (Sandbox Code Playgroud)
在非常合理的桌面和高速连接上,程序非常慢.尝试使用ScrollBar滚动...说到中间,需要30秒.点击"主页"和"结束"键将花费大量时间.
这不是第一次只能获取图像到缓存的问题.来回看看已经呈现的图片有点快,但通常很慢.似乎没有任何内容存储在缓存中,关闭应用程序并重新启动它,一切都很慢.
等效的HTML代码快速消失.有些慢,第一次,但后来一切都很快.
到底是怎么回事?元素是否使用任何缓存?列表是否对当前未显示的图像进行预取?无论如何要告诉它吗?真的,我唯一的解决方案是自己管理Bitmap对象,以及缓存和预取逻辑吗?如果是这样,我可以合并以前的任何工作?
编辑(摘要):
ListBoxes默认情况下虚拟化项目,因此如果向下滚动,则会动态创建项目.首先,它需要下载图像,然后对其进行解码.如果您滚动浏览了所有图像,它们可能会被缓存,但ListBox仍然会重新创建Image控件,因此每次都需要再次解码图像.
您可以通过将VirtualizingStackPanel.IsVirtualizing附加属性设置为falseon 来关闭虚拟化,ListBox然后立即加载所有内容,或者您可以更改VirtualizationModeto Recycling,然后Images(和包含ListBoxItems)一旦创建就不会被丢弃.