C# 使用线程池异步加载图像
我想将未知数量的图像加载到ListView中。每个图像都有其ViewModel,其缩略图属性保存图像数据。当图像被访问且尚未加载时,我希望返回null,但同时使用线程池启动加载过程C# 使用线程池异步加载图像,c#,wpf,xaml,C#,Wpf,Xaml,我想将未知数量的图像加载到ListView中。每个图像都有其ViewModel,其缩略图属性保存图像数据。当图像被访问且尚未加载时,我希望返回null,但同时使用线程池启动加载过程 public BitmapSource Thumbnail { get { if (_thumbnail == null) { loadThu
public BitmapSource Thumbnail
{
get
{
if (_thumbnail == null)
{
loadThumbnail(this);
}
return _thumbnail;
}
private set
{
_thumbnail = value;
OnPropertyChanged(nameof(Thumbnail));
}
}
private static void loadThumbnail(ImageViewModel ivm)
{
ThreadPool.QueueUserWorkItem(o =>
{
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.DecodePixelWidth = 100;
bi.CacheOption = BitmapCacheOption.OnLoad;
bi.UriSource = new Uri(ivm.FilePath);
bi.EndInit();
bi.Freeze();
ivm.Dispatcher.Invoke(DispatcherPriority.DataBind, new setThumbnailCallback(ivm.setThumbnail), bi );
});
}
public delegate void setThumbnailCallback(BitmapSource image);
private void setThumbnail(BitmapSource image)
{
Thumbnail = image;
}
XAML如下所示(由ListView调用):
当我显示ListView时,前几个图像加载得很好,但随后它停止了。一段时间后,会出现更多的漏洞,但列表中有一些漏洞从未加载。我这里不是说前1000张,而是前20张中的15张被加载,几秒钟后图像40-45,而20-39保持空白。其余的永远不会上膛。也就是说,未加载的图像总是相同的,但在大小和位置上没有明显的差异
Task.Factory.StartNew(新操作(()=>
具有相同的行为。更改DispatcherPriority
也不会更改任何内容
如果我使用缩略图转换器和IsAsync标记加载图像,程序需要大约一秒钟的时间才能加载所有图像而不会出现问题(因此没有性能问题).但我不想这样做,因为这意味着加载的图像在视图中,而不是ViewModel中,这会夺走控制权,如果在另一个视图中重复使用它,会浪费内存,并且以后必须重新加载它(更不用说启动的数百个线程)
所以我的问题是,图像加载速度不仅较慢,而且在某些部分根本不会加载。我缺少了什么
提前感谢。您不必调用dispatcher来设置视图模型的属性。如果您只需启动一个新的
任务,创建位图图像并设置源属性,会怎么样
private static void loadThumbnail(ImageViewModel ivm)
{
Task.Run(() =>
{
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.DecodePixelWidth = 100;
bi.CacheOption = BitmapCacheOption.OnLoad;
bi.UriSource = new Uri(ivm.FilePath);
bi.EndInit();
bi.Freeze();
ivm.Thumbnail = bi;
});
}
需要注意的是,loadThumbnail方法是静态的,但只接受一个ImageViewModel参数,这似乎有些奇怪
?也就是说,如果将Invoke
替换为BeginInvoke
,会产生与映像数量相同的任务,这是线程池要防止的。是的,它会创建与映像数量相同的任务,但默认任务计划程序使用线程池来执行任务:.ThreadPool.QueueUserWorkItem基本上是一种在线程池上运行某些工作的较旧且不受欢迎的方式。
private static void loadThumbnail(ImageViewModel ivm)
{
Task.Run(() =>
{
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.DecodePixelWidth = 100;
bi.CacheOption = BitmapCacheOption.OnLoad;
bi.UriSource = new Uri(ivm.FilePath);
bi.EndInit();
bi.Freeze();
ivm.Thumbnail = bi;
});
}