【问题标题】:Images not appearing on WPF form when loading asynchronously异步加载时图像未出现在 WPF 表单上
【发布时间】:2015-08-30 08:14:39
【问题描述】:

我正在尝试显示(在具有自定义 DataTemplate 的 ListBox 中)从多页 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 线程无法访问保存图像数据的源属性以在表单上显示它们(这就是我尝试冻结的原因)。

任何想法将不胜感激!

示例图片:http://i.imgur.com/75wMkmS.png

【问题讨论】:

  • 不知道为什么冻结不起作用,您可以在这里查看其他一些建议:stackoverflow.com/questions/3034902/…
  • 感谢您的链接 - 我一直在研究这些建议,看看是否有任何解决方法。附上一张图,希望能给个推荐:i.imgur.com/75wMkmS.png左边是UI线程处理结果,右边是BackgroundWorker/async版本。
  • 您是否在任何地方关闭 FileStream?为确保立即加载所有帧并且在创建 BitmapFrames 后可以立即关闭流,您应该设置 BitmapCacheOption.OnLoad 而不是 Default
  • @Clemens,您对BitmapCacheOption.OnLoad 的建议成功了!感谢您的帮助!

标签: c# wpf multithreading listbox backgroundworker


【解决方案1】:

@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");

    }

【讨论】:

    猜你喜欢
    • 2013-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多