简体   繁体   English

c#wpf使用Dispatcher从BlockingCollection更新UI源

[英]c# wpf Updating UI source from BlockingCollection with Dispatcher

Here's my problem. 这是我的问题。
I'm loading a few BitmapImages in a BlockingCollection 我正在BlockingCollection中加载一些BitmapImages

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

the loading happens in a backgroungwork thread. 加载发生在背景工作线程中。

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

debugging this part of the code everything looks okay, the problem comes now ... 调试这部分代码看起来一切正常,问题就来了...

after finishing loading the images I want to show them in UI one by one. 加载完图像后,我想在UI中一张一张地显示它们。 I'm using a dispatcher to do so but I always get the message telling me that the called Thread can not access the object because it belongs to a different 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);
        }
    }

debug accuses that the error is here 调试指出错误在这里

                this.dstSource.Source = item;

I'm trying everything but cant find out what's wrong. 我正在尝试一切,但无法找出问题所在。 Anyone has any idea? 有人知道吗?

You have to call Freeze after loading the images in order to make them accessible to other threads: 您必须在加载图像后调用Freeze ,以使其他线程可以访问它们:

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

As far as I have understood the BitmapCacheOption.OnLoad flag, it is only effective when a BitmapImage is loaded from a stream. 据我了解BitmapCacheOption.OnLoad标志,它仅在从流中加载BitmapImage时才有效。 The Remarks section in BitmapCacheOption says: BitmapCacheOption中的 “备注”部分说:

Set the CacheOption to BitmapCacheOption.OnLoad if you wish to close a stream used to create the BitmapImage. 如果您希望关闭用于创建BitmapImage的流,请将CacheOption设置为BitmapCacheOption.OnLoad。 The default OnDemand cache option retains access to the stream until the image is needed, and cleanup is handled by the garbage collector. 默认的OnDemand缓存选项将保留对流的访问,直到需要映像为止,并且清理由垃圾收集器处理。

A BitmapImage created from a Uri may be loaded asynchronously (see the IsDownloading property). 从Uri创建的BitmapImage可以异步加载(请参见IsDownloading属性)。 Consequently, Freeze may not be callable on such a BitmapImage, as downloading may still be in progress after EndInit. 因此, Freeze可能无法在这样的BitmapImage上调用,因为在EndInit之后下载可能仍在进行中。 I guess it nevertheless works in your case because you are loading BitmapImages from file Uris, which seems to be done immediately. 我想它仍然适用于您的情况,因为您正在从文件Uris加载BitmapImages,这似乎可以立即完成。

To avoid this potential problem you may just create the BitmapImage from a FileStream: 为避免此潜在问题,您可以仅从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();
}

For the further future readers, here is the code I used to fix my problem. 对于以后的读者来说,这是我用来解决问题的代码。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM