考虑以下示例XAML文件,它显示了Facebook的前1000个人,从第4个人markz开始。请注意,这只是一个示例。任何具有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>
而代码背后:
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;
}
}
在一台配置合理且网络速度很快的电脑上,该程序运行极慢。尝试使用滚动条滚动到中间位置需要花费30秒钟的时间。按下“Home”和“End”键也需要相当长的时间。
这不是首次获取图片缓存的问题。来回切换查看已经呈现的图片会稍微快一些,但通常仍然很慢。似乎没有任何东西被存储在缓存中,关闭应用程序并重新启动后,一切又变得很慢。
等效的HTML代码执行非常快。第一次会有些慢,但之后一切都非常快。
发生了什么?列表元素是否使用任何缓存?列表是否预先获取当前未显示的图像?有没有办法告诉它去做?我的唯一解决方案就是自己管理位图对象,以及缓存和预取逻辑吗?如果是的话,有哪些之前的工作我可以整合?
编辑(总结):
1.关闭虚拟化将会给出最佳结果,整个列表框在窗口加载时渲染,不会重新计算任何图像。
2.Phil的代码非常好用,特别是来回切换时可以提高性能。
3.没有任何额外的代码,WPF不会在调用之间缓存图像。WinINET缓存未被使用。尽管请求在HTTP头中带有缓存指令,但WPF不会对其进行任何操作。