在异步加载时,图像不出现在WPF表单上

时间:2015-06-14 21:49:41

标签: c# wpf multithreading listbox backgroundworker

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

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

我试图冻结缩略图(没有好处),尝试将它们发送回UI线程,然后通过worker的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

1 个答案:

答案 0 :(得分:2)

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

    }