WPF-将多个图像逐个加载到ObservableCollection中

WPF-将多个图像逐个加载到ObservableCollection中,wpf,image,backgroundworker,observablecollection,dispatcher,Wpf,Image,Backgroundworker,Observablecollection,Dispatcher,在WPF中,我试图将许多(数千)个图像加载到ListBox包装中 我正在尝试加载与Windows资源管理器窗口类似的图像 到目前为止,我的代码加载了所有图像的名称、位置(作为标记)和占位符图像,以加快加载时间: Dim ofd As New Microsoft.Win32.OpenFileDialog() ofd.Multiselect = True ofd.Filter = "JPEG|*.jpg" If ofd.ShowDialog() Then For Each f In ofd.

在WPF中,我试图将许多(数千)个图像加载到ListBox包装中

我正在尝试加载与Windows资源管理器窗口类似的图像

到目前为止,我的代码加载了所有图像的名称、位置(作为标记)和占位符图像,以加快加载时间:

Dim ofd As New Microsoft.Win32.OpenFileDialog()
ofd.Multiselect = True
ofd.Filter = "JPEG|*.jpg"

If ofd.ShowDialog() Then
   For Each f In ofd.FileNames
      Items.Add(New With {.img = New BitmapImage(New Uri("pack://application:,,,/Resources/PlaceholderPhoto.png")), .nam = Path.GetFileNameWithoutExtension(f), .tag = f})
   Next

  'The name of my ObservableCollection is Items'
  lstboxPhotos.ItemsSource = Items 
End If
那部分很好。之后我要做的是动态加载图像的缩略图(一个接一个)。我这样做是为了让用户可以在加载缩略图时与之交互并查看有多少图像可用。我尝试了两种不同的方法——后台工作程序、调度程序和独立线程

我用来加载图像的代码如下:

    'i came from me doing a for..next for each image in Items collection'
    Dim bmp As New BitmapImage()
    bmp.BeginInit()
    bmp.DecodePixelWidth = 90
    bmp.DecodePixelHeight = 60
    bmp.CacheOption = BitmapCacheOption.OnLoad
    bmp.UriSource = New Uri(Items.Item(i).tag, UriKind.Absolute)
    bmp.EndInit()

    Items.Item(i).img = bmp
我在互联网上到处搜索。老实说,我不确定该朝什么方向去做我需要做的事情

如果我还需要澄清什么,请告诉我。先谢谢你!:)

编辑: 好的,参考,使用第二个答案,我一次加载一个项目。它可以加载所有项目的名称,但似乎在加载了大约40个项目后停止加载图像


如果有人能解释为什么它可能会停止加载缩略图,但继续加载项目的名称,这将是一个很大的帮助!谢谢

您可以使用内置的
TypeConverter
string
文件路径转换为
ImageSource
对象,快速轻松地完成此操作。以这个简单的示例为例,它将显示
Pictures
文件夹中所有图像的缩略图:

public ObservableCollection<string> FilePaths { get; set; }
publicobservableCollection文件路径{get;set;}

filepath=newobserveCollection(Directory.GetFiles(
GetFolderPath(Environment.SpecialFolder.MyPictures));



在本例中,每个
Image.Source
属性都是直接与
filepath
集合中的一个文件路径绑定的数据。

好吧,我知道已经有一段时间了,但我想发布我最后做的事情

首先,我通常使用带有临时图像的
ObservableCollection
将所有图像名称加载到列表框中:

Dim Items As New ObservableCollection(Of Object)
Dim Files() As String
...

For Each f In Files
    Items.Add(New With {.img = New BitmapImage(New Uri("/Resources/Photo.png")), .name = f})
Next

lbPhotos.ItemsSource = Items
然后我使用
BackgroundWorker
将每个占位符图像替换为实际图像:

Private WithEvents bw As New BackgroundWorker
Private Sub bw_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles bw.DoWork
    ...

    For i = 0 To Items.Count - 1
        If bw.CancellationPending Then
            e.Cancel = True
        Else
            Dim n As String = Items(i).name
            Dim t As String = Items(i).tag

            Dim bmp As New BitmapImage
            bmp.BeginInit()                
            bmp.UriSource = New Uri(PathToImage, UriKind.Absolute)
            bmp.EndInit()
            bmp.Freeze()

            Dispatcher.BeginInvoke(Sub()
                                       Items.RemoveAt(i)
                                       Items.Insert(i, New With {.img = bmp, .name = n})
                                   End Sub)
        End If
    Next
End Sub

这允许用户在加载图像时与UI交互。

在当前方法中,可能会消耗过多内存。也许也会减慢应用程序的速度。如果大约有数千张图像,请选择
虚拟化
。如果在将项目添加到ObservableCollection时加载缩略图,则速度会很慢。当我使用当前使用的占位符方法时,速度并不慢。我只希望每个图像在加载时显示,但仍然允许用户与列表框交互。谢谢你的回复!你被困在哪里了?我的意思是,除了寻找方向,这里还有什么问题?对不起!我想我是在问我如何在不冻结UI的情况下用集合更新ListBox ItemsSource?我将集合中每个项目的占位符图像替换为正确的缩略图。更新集合中的项目后,我希望它在列表框中显示新的缩略图。我没能做到(这里有一个建议,只在集合中存储图像路径,绑定到列表框,并为列表框定义一个数据模板,同时使用容器异步加载图像,同时显示占位符。我不在电脑旁,我可以在回家后尝试一下,你可以在这期间给它一次机会。好的,我得到了它n。)哦,但它仍然只是一次加载所有图像,然后将它们作为一个整体显示。我希望它在加载图像时显示图像。您需要确保动态填充FilePath属性-创建另一个线程并开始添加文件路径,每组5个,然后通过Dispatcher将它们发送到主UI线程并将它们添加到o FilePaths observableCollection。确保在添加之间进行一点睡眠,大约15毫秒。这样可以获得想要的效果。
Dim Items As New ObservableCollection(Of Object)
Dim Files() As String
...

For Each f In Files
    Items.Add(New With {.img = New BitmapImage(New Uri("/Resources/Photo.png")), .name = f})
Next

lbPhotos.ItemsSource = Items
Private WithEvents bw As New BackgroundWorker
Private Sub bw_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles bw.DoWork
    ...

    For i = 0 To Items.Count - 1
        If bw.CancellationPending Then
            e.Cancel = True
        Else
            Dim n As String = Items(i).name
            Dim t As String = Items(i).tag

            Dim bmp As New BitmapImage
            bmp.BeginInit()                
            bmp.UriSource = New Uri(PathToImage, UriKind.Absolute)
            bmp.EndInit()
            bmp.Freeze()

            Dispatcher.BeginInvoke(Sub()
                                       Items.RemoveAt(i)
                                       Items.Insert(i, New With {.img = bmp, .name = n})
                                   End Sub)
        End If
    Next
End Sub