C# 使用WPF在线程中加载图像
我正在尝试制作一个列表框来显示来自互联网的图片。通过将itemsource绑定到包含图像URL和一些其他属性title、desc等的模型来提供这些项 不幸的是,加载列表的速度非常慢,因为WPF试图在显示列表之前从web下载所有图片,这会使应用程序冻结15到25秒 我已经读到我应该在另一个线程加载图片,但我不知道我应该在哪里做,如何做?直接在模型中加载所有图片是否更好?只为此创建一个线程池,但问题是它实际上不是模型/模型视图的一部分,还是创建一个背景线程,在列表有数据时直接更新列表更好C# 使用WPF在线程中加载图像,c#,wpf,image,list,multithreading,C#,Wpf,Image,List,Multithreading,我正在尝试制作一个列表框来显示来自互联网的图片。通过将itemsource绑定到包含图像URL和一些其他属性title、desc等的模型来提供这些项 不幸的是,加载列表的速度非常慢,因为WPF试图在显示列表之前从web下载所有图片,这会使应用程序冻结15到25秒 我已经读到我应该在另一个线程加载图片,但我不知道我应该在哪里做,如何做?直接在模型中加载所有图片是否更好?只为此创建一个线程池,但问题是它实际上不是模型/模型视图的一部分,还是创建一个背景线程,在列表有数据时直接更新列表更好 谢谢 一个
谢谢 一个非常简单的方法是在视图模型中使用System.ComponentModel.BackgroundWorker。下面是一个简单的例子:
using (BackgroundWorker bg = new BackgroundWorker())
{
bg.DoWork += (sender, args) => FetchImages(viewModelObjectsNeedingImages);
bg.RunWorkerAsync();
}
BackgroundWorker还可以非常方便地取消后台任务
你可能还想看看 一个非常简单的方法是在视图模型中使用System.ComponentModel.BackgroundWorker。下面是一个简单的例子:
using (BackgroundWorker bg = new BackgroundWorker())
{
bg.DoWork += (sender, args) => FetchImages(viewModelObjectsNeedingImages);
bg.RunWorkerAsync();
}
BackgroundWorker还可以非常方便地取消后台任务
你可能还想看看 您可以使用将数据源绑定到列表框,并且仍然可以将数据加载到另一个线程中
有关如何编写这样一个线程的示例,请查看文档
此外,您可能需要考虑对图像的懒惰加载,即只加载可见的和在任何时候多的图像。通过这种方式,您可以获得两个好处:在获取线程中的图像时不必阻塞UI,并且您可以重用您的集合,一次只保存几个图像,防止在计划显示(比如)几千个图像时,一次用大量图像填充内存。查看有关如何实现这种虚拟化的详细信息。
您可以使用它将数据源绑定到列表框,并且仍然可以在另一个线程中加载数据 有关如何编写这样一个线程的示例,请查看文档此外,您可能需要考虑对图像的懒惰加载,即只加载可见的和在任何时候多的图像。通过这种方式,您可以获得两个好处:在获取线程中的图像时不必阻塞UI,并且您可以重用您的集合,一次只保存几个图像,防止在计划显示(比如)几千个图像时,一次用大量图像填充内存。查看有关如何实现此类虚拟化的详细信息。
简单的方法是只需设置Binding.IsAsync属性,如下所示:<Image ImageSource="{Binding propertyThatComputesImageSource, IsAsync=true}" />
如果模型的属性是DependencyProperty,则可能需要使用Dispatcher.Invoke或两个来扩展,因为它们不能从单独的线程访问
这项技术可以扩展到产生固定数量的工作人员来加载图像,并中断它们之间的工作,以便进行多个图像下载,但同时下载的数量是有限的,因此您不会有数百个线程。简单的方法是只需设置Binding.IsAsync属性,如下所示:
<Image ImageSource="{Binding propertyThatComputesImageSource, IsAsync=true}" />
如果模型的属性是DependencyProperty,则可能需要使用Dispatcher.Invoke或两个来扩展,因为它们不能从单独的线程访问
这项技术可以扩展到产生固定数量的工作人员来加载图像,并将它们之间的工作分解,这样就可以进行多个图像下载,但同时下载的数量是有限的,这样您就不会有数百个线程。感谢大家
所有的解决方案都应该有效:在我的例子中,在ListBoxItem的图像上使用IsAsync就足够了,最多有50个项目。事实上,它并不是从网络上检索图像,这花费了太多的时间
不幸的是我的问题出在别的地方。。。这与.NET 3.5中的代理检测错误有关,该错误导致应用程序加载非常缓慢:
如果应用程序文件夹中没有包含以下代码的\u application\u name.exe.config文件-.NET可能需要大量时间来检测代理,该代理会在应用程序首次访问网络时冻结应用程序:
<configuration>
<system.net>
<defaultProxy enabled="false"/>
</system.net>
</configuration>
谢谢大家
所有的解决方案都应该有效:在我的例子中,在ListBoxItem的图像上使用IsAsync就足够了,最多有50个项目。事实上,它并不是从网络上检索图像,这花费了太多的时间
不幸的是我的问题出在别的地方。。。这与.NET 3.5中的代理检测错误有关,该错误导致应用程序加载非常缓慢:
如果应用程序文件夹中没有任何包含t的\u应用程序\u name.exe.config文件
以下代码-.NET可能需要花费大量时间来检测代理,该代理在应用程序首次访问网络时会冻结应用程序:
<configuration>
<system.net>
<defaultProxy enabled="false"/>
</system.net>
</configuration>
只要确保SynchronizationContext.Current在BackgroundWorker启动时是有意义的。应该是WPF上下文,但要记住。请确保SynchronizationContext.Current在BackgroundWorker启动时有意义。应该是WPF上下文,但只是需要记住的东西。