C# 使用TPL向图像控件呈现程序图标

C# 使用TPL向图像控件呈现程序图标,c#,wpf,behavior,task-parallel-library,C#,Wpf,Behavior,Task Parallel Library,嗨,我正在尝试创建一个交互性。在后台加载程序图标的行为。下面是代码,但它给了我调用线程无法访问此对象的消息,因为它是另一个线程拥有的 protected override void OnAttached() { base.OnAttached(); if (!string.IsNullOrEmpty(Url)) { Icon ico = Icon.ExtractAssociatedIcon(Url);

嗨,我正在尝试创建一个交互性。在后台加载程序图标的行为。下面是代码,但它给了我调用线程无法访问此对象的消息,因为它是另一个线程拥有的

protected override void OnAttached()
    {
        base.OnAttached();

        if (!string.IsNullOrEmpty(Url))
        {
            Icon ico = Icon.ExtractAssociatedIcon(Url);
            if (ico != null)
            {

               taskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
                Task.Factory.StartNew(() => {
                                                MemoryStream ms = new MemoryStream();
                                                ico.ToBitmap().Save(ms, ImageFormat.Png);
                                                ms.Position = 0;
                                                BitmapImage bi = new BitmapImage();
                                                bi.BeginInit();
                                                bi.StreamSource = ms;
                                                bi.EndInit();
                                                return bi;
                                            }).ContinueWith((t) => AssociatedObject.Source = t.Result, taskScheduler);




            }

        }
    }

尽管您使用的是CurrentSynchronizationContext,但如果必须在图标的
调度程序上运行,请尝试一下

    ico.Dispatcher.BeginInvoke(
         new Action(
           () =>
           {
              ico.ToBitmap().Save(ms, ImageFormat.Png); 
              ///rest of the code that uses `ms`.
           }));
建议:为什么不使用
优先级绑定
绑定.IsAsync
来缓慢加载图像

WPF对象(从其派生的任何对象)是线程仿射对象——通常它们只能在创建它们的线程上使用。这包括对象。如果在后台线程上创建BitmapImage,则只能从该后台线程使用它——这意味着UI线程在尝试显示位图时会出错

但是,BitmapImage从。Freezable有一个方法可以使实例只读。并根据MSDN上的“”:

冻结的Freezable也可以跨线程共享,而未冻结的Freezable则不能


因此,如果您添加对
bi.Freeze()的调用
在您从后台任务返回图像之前,您应该能够从UI线程成功使用图像。

谢谢。。我今天学到了一些新东西……;)但是…我尝试将AssociatedObject.Source=bi放入任务的操作委托中,并使用Task.Factory.StartNew(()=>..,CancellationToken.None,TaskCreationOptions.None,taskScheduler);而且它也有效。。。。区别是什么?如果使用
TaskScheduler.FromCurrentSynchronizationContext
启动任务,则在当前线程中运行它。您最好根本不使用任务。