【问题标题】:WPF - Loading many images into ObservableCollection One by OneWPF - 将许多图像一张一张地加载到 ObservableCollection 中
【发布时间】:2014-08-01 15:06:39
【问题描述】:

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

我正在尝试以类似于 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

我在整个互联网上进行了搜索。老实说,我不确定要采取什么方向来做我需要做的事情。

如果我需要澄清其他任何事情,请告诉我。先感谢您! :)

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

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

【问题讨论】:

  • 在您当前的方法中,您可能会消耗过多的内存。也许也会减慢应用程序的速度。如果大约有数千张图片,请选择Virtualization
  • 如果我在将项目添加到 ObservableCollection 时加载缩略图会很慢。当我使用我当前使用的占位符方法时,它并不慢。我只希望每个图像在加载时显示,但仍然允许用户与 ListBox 交互。感谢您的回复!
  • 那么你卡在哪里了?我的意思是除了寻找方向之外,这里还有什么问题?
  • 对不起!我想我在问如何在不冻结 UI 的情况下使用集合更新 ListBox ItemsSource?我正在用正确的缩略图替换集合中每个项目的占位符图像。更新集合中的项目后,我希望它在 ListBox 中显示新的缩略图。我没能做到这一点。 :(
  • 这里有个建议,只存储集合中的图片路径,绑定listbox,为listbox定义数据模板,使用容器异步加载图片,同时显示占位符.我的电脑不在身边,回家后我可能会尝试一下,同时您也可以试一试。

标签: wpf image backgroundworker observablecollection dispatcher


【解决方案1】:

您可以使用内置的TypeConverterstring 文件路径转换为ImageSource 对象,从而快速轻松地做到这一点。举个简单的例子,它会显示您的Pictures 文件夹中所有图像的缩略图:

public ObservableCollection<string> FilePaths { get; set; }

...

FilePaths = new ObservableCollection<string>(Directory.GetFiles(
    Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)));

...

<ItemsControl ItemsSource="{Binding FilePaths}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Image Source="{Binding}" Width="100" Stretch="Uniform" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

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

【讨论】:

  • 好的,我现在知道了,但它仍然只是一次加载所有图像,然后将它们作为一个整体显示。我希望它在加载时显示图像。
  • 您需要确保 FilePaths 属性被动态填充 - 创建另一个线程并开始添加一组 5 个文件路径,然后通过 Dispatcher 将它们发送到主 UI 线程并将它们添加到 FilePaths observableCollection。确保在添加之间稍作睡眠,大约 15 毫秒。这样你就可以得到你想要的效果。
【解决方案2】:

好的,我知道已经有一段时间了,但我想发布我最终做了什么。

首先,我通常使用带有临时图像的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 进行交互。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-23
    • 1970-01-01
    • 2011-01-29
    • 1970-01-01
    • 2013-07-18
    • 2016-05-02
    • 2010-11-07
    • 1970-01-01
    相关资源
    最近更新 更多