C#WPF从BlockingCollection更新UI源与分派器(c# wpf Updating

2019-08-31 10:49发布

这里是我的问题。
我加载了几个BitmapImages在BlockingCollection

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

装载发生在backgroungwork线程。

    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之一。 我使用的是调度员这样做,但我总是得到的消息告诉我,因为它属于一个不同的线程调用Thread不能访问该对象。

    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);
        }
    }

调试指责的错误是在这里

                this.dstSource.Source = item;

我想一切,但不能找出什么是错的。 任何人有任何想法?

Answer 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。 默认按需缓存选项保留访问,直到所需要的图像的流,和清理是由垃圾收集处理。

从URI创建的BitmapImage的可被异步加载(见IsDownloading属性)。 因此, Freeze可能不是这样的BitmapImage的调用,因为下载可能仍在EndInit后的进展。 我猜它仍然工作在你的情况,因为你是从装载档案URI,这似乎是立即进行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();
}


Answer 2:

为了进一步未来的读者,这里是我用来解决我的问题的代码。

    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;
    }


文章来源: c# wpf Updating UI source from BlockingCollection with Dispatcher