异步加载时图像未显示在 WPF 窗体上

本文关键字:WPF 窗体 显示 加载 图像 异步 | 更新日期: 2023-09-27 17:56:24

>我正在尝试显示(在具有自定义数据模板的列表框中)从多页 tiff 图像中提取的一系列 BitmapSource 帧(缩略图)。 当我在 UI 线程上处理 tiff 时,或者直接将图像添加到列表框的项集合中,或者将它们添加到绑定的 ObservableCollection 中,它们在列表中显示正常。 但是,当尝试异步加载每个缩略图(使用 BackgroundWorker 或使用异步任务)时,我看到我无法解决的行为:

  • 第一个缩略图按预期加载
  • 下一个和所有后续缩略图都会在列表中获取项目(我看到边框),但显示的只是空白图像。 它显示正确的项目数,但第一个项目之后没有图像。
我已经尝试冻结

缩略图(不好),尝试将它们发送回 UI 线程并通过工作人员的 ReportProgress 将它们添加到那里的集合中(不好),但我似乎无法让它们显示。

处理 UI 线程(其中 SyncImages 是绑定到我的 ListBox 的 ObservableCollection,OnPropertyChanged 处理通知事件):

private void LoadSynchronous()
{
    Stream imageStreamSource = new FileStream(ImagePath, FileMode.Open, FileAccess.Read, FileShare.Read);
    var decoder = BitmapDecoder.Create(imageStreamSource, BitmapCreateOptions.PreservePixelFormat,
        BitmapCacheOption.Default);
    foreach (var frame in decoder.Frames)
    {
        //frame.Freeze();  //Tried this but no effect.
        SyncImages.Add(frame);
    }
    OnPropertyChanged("SyncImages");
}

不起作用(此示例将框架直接添加到列表中,但我也尝试通过绑定,结果没有差异):

private void LoadAsync(object sender, DoWorkEventArgs e)
{
    Stream imageStreamSource = new FileStream(ImagePath, FileMode.Open, FileAccess.Read, FileShare.Read);
    var decoder = BitmapDecoder.Create(imageStreamSource, BitmapCreateOptions.PreservePixelFormat,
        BitmapCacheOption.Default);
    foreach (var frame in decoder.Frames)
    {
        // frame.Freeze();
        (sender as BackgroundWorker).ReportProgress(0, frame);
    }
    OnPropertyChanged("AsyncImages");
}
private void ReportAsyncProgress(object send, ProgressChangedEventArgs e)
    {
        var frame = (BitmapSource) e.UserState;
        LbAsynchronous.Items.Add(frame);
    }

希望有人能阐明这里发生的事情。 我知道代码可以提取帧,因此即使在异步示例中也必须加载它们,但似乎 UI 线程无法访问保存图像数据的源的属性以将它们显示在表单上(这就是我尝试冻结的原因)。

任何想法将不胜感激!

示例图像:https://i.stack.imgur.com/xsarz.png

异步加载时图像未显示在 WPF 窗体上

@Clemens他对

原始问题的评论中的回答提供了解决方案。 确保以负责任的方式关闭文件流并将BitmapCacheOption更改为OnLoad现在会显示异步加载中的每个图像。

异步加载的最终代码如下所示:

private void LoadAsync(object sender, DoWorkEventArgs e)
    {
        BitmapDecoder decoder;
        using (Stream imageStreamSource = new FileStream(ImagePath, FileMode.Open, FileAccess.Read, FileShare.Read))
        {
            decoder = BitmapDecoder.Create(imageStreamSource, BitmapCreateOptions.PreservePixelFormat,
                BitmapCacheOption.OnLoad);
        }
        foreach (var frame in decoder.Frames)
        {
            frame.Freeze();
            (sender as BackgroundWorker).ReportProgress(0, frame);
        }
    }
    private void UpdateAsync(object send, ProgressChangedEventArgs e)
    {
            SyncImages.Add((BitmapSource)e.UserState);
            OnPropertyChanged("SyncImages");
    }