0

这是我的问题。
我在 BlockingCollection 中加载了一些 BitmapImages

    public void blockingProducer(BitmapImage imgBSource)
    {
        if (!collection.IsAddingCompleted)
            collection.Add(imgBSource);
    }

加载发生在背景工作线程中。

    private void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        String filepath; int imgCount = 0;

        for (int i = 1; i < 10; i++)
        {
            imgCount++;

            filepath = "Snap";
            filepath += imgCount;
            filepath += ".bmp";

            this.Dispatcher.BeginInvoke(new Action(() =>
            {
                label1.Content = "Snap" + imgCount + " loaded.";
            }), DispatcherPriority.Normal);

            BitmapImage imgSource = new BitmapImage();
            imgSource.BeginInit();
            imgSource.UriSource = new Uri(filepath, UriKind.Relative);
            imgSource.CacheOption = BitmapCacheOption.OnLoad;
            imgSource.EndInit();

            blockingProducer(imgSource);
        }
    }

调试这部分代码一切正常,现在问题来了...

完成加载图像后,我想在 UI 中一张一张地显示它们。我正在使用调度程序来执行此操作,但我总是收到消息,告诉我被调用的线程无法访问该对象,因为它属于不同的线程。

    public void display(BlockingCollection<BitmapImage> results)
    {
        foreach (BitmapImage item in collection.GetConsumingEnumerable())
        {
            this.Dispatcher.BeginInvoke(new Action(() =>
            {
                this.dstSource.Source = item;
                Thread.Sleep(250);
            }), DispatcherPriority.Background);
        }
    }

debug 指责错误在这里

                this.dstSource.Source = item;

我正在尝试一切,但无法找出问题所在。有人有什么想法吗?

4

2 回答 2

1

您必须Freeze在加载图像后调用以使其他线程可以访问它们:

BitmapImage imgSource = new BitmapImage();
imgSource.BeginInit();
imgSource.UriSource = new Uri(filepath, UriKind.Relative);
imgSource.CacheOption = BitmapCacheOption.OnLoad;
imgSource.EndInit();
imgSource.Freeze(); // here

据我了解该BitmapCacheOption.OnLoad标志,它仅在从流中加载 BitmapImage 时有效。BitmapCacheOption中的备注部分说:

如果您希望关闭用于创建 BitmapImage 的流,请将 CacheOption 设置为 BitmapCacheOption.OnLoad。默认的 OnDemand 缓存选项保留对流的访问,直到需要图像为止,并且清理由垃圾收集器处理。

从 Uri 创建的 BitmapImage 可以异步加载(请参阅IsDownloading属性)。因此,Freeze可能无法在此类 BitmapImage 上调用,因为在 EndInit 之后下载可能仍在进行中。我想它仍然适用于您的情况,因为您正在从文件 Uris 加载 BitmapImages,这似乎是立即完成的。

为了避免这个潜在的问题,您可以只从 FileStream 创建 BitmapImage:

var imgSource = new BitmapImage();

using (var stream = new FileStream(filepath, FileMode.Open))
{
    imgSource.BeginInit();
    imgSource.StreamSource = stream;
    imgSource.CacheOption = BitmapCacheOption.OnLoad;
    imgSource.EndInit();
    imgSource.Freeze();
}
于 2013-04-18T05:34:17.297 回答
0

对于未来的读者,这是我用来解决问题的代码。

    public void display(BlockingCollection<BitmapImage> collection)
    {
        if (collection.IsCompleted || collection.Count != 0)
        {
            BitmapImage item = collection.Take();
            this.Dispatcher.BeginInvoke(new Action(() =>
            {
                this.dstSource.Source = item;

            }), DispatcherPriority.Normal);
        }
        else
        {
            dispatcherTimer.Stop();
        }
    }

    public void dispatcherTimer_Tick(object sender, EventArgs e)
    {
        display(collection);
    }

    public void configureDispatcherTimer()
    {
        dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
        TimeSpan interval = TimeSpan.FromMilliseconds(150);
        dispatcherTimer.Interval = interval;
    }
于 2013-04-18T19:13:13.293 回答