C# 使用线程池异步加载图像

C# 使用线程池异步加载图像,c#,wpf,xaml,C#,Wpf,Xaml,我想将未知数量的图像加载到ListView中。每个图像都有其ViewModel,其缩略图属性保存图像数据。当图像被访问且尚未加载时,我希望返回null,但同时使用线程池启动加载过程 public BitmapSource Thumbnail { get { if (_thumbnail == null) { loadThu

我想将未知数量的图像加载到ListView中。每个图像都有其ViewModel,其缩略图属性保存图像数据。当图像被访问且尚未加载时,我希望返回null,但同时使用线程池启动加载过程

    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;
    });
}