使用TPL将图像控件呈现给图像控件

问题描述:

嗨,我试图创建一个Interactivity.Behavior在后台加载程序的图标。以下是代码,但它给我的调用线程,因为不同的线程拥有它无法访问该对象..使用TPL将图像控件呈现给图像控件

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




      } 

     } 
    } 

WPF对象(任何从DispatcherObject下降的东西)都是线程仿射的 - 通常它们只能在创建它们的线程上使用。这包括BitmapImage对象。如果您在后台线程上创建BitmapImage,那么只能从后台线程使用 - 这意味着UI线程在尝试显示位图时会出现错误。

但是,BitmapImage从Freezable下降。 Freezable有一个Freeze方法将使实例只读。并根据MSDN上的“Freezable Objects Overview”:

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

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

+0

THanks ..我今天学到了一些新东西...;) 但是...我试着将AssociatedObject.Source = bi放在Task的Action委托中,并使用Task.Factory.StartNew(()=> .. ..,CancellationToken.None,TaskCreationOptions.None,taskScheduler);它的工作原理也是......有什么区别? – icube

+0

如果使用'TaskScheduler.FromCurrentSynchronizationContext'启动任务,则在当前线程中运行它。你完全可以不使用任务。 –

虽然使用的是CurrentSynchronizationContext,给它一个尝试,如果可能不得不在Dispatcher运行图标....

ico.Dispatcher.BeginInvoke(
     new Action(
      () => 
      { 
       ico.ToBitmap().Save(ms, ImageFormat.Png); 
       ///rest of the code that uses `ms`. 
      })); 

建议:为什么你的arent使用Priority BindingBinding.IsAsync慢加载图像....

http://social.msdn.microsoft.com/Forums/en-AU/wpf/thread/b3dc9baa-4cf6-49ed-a316-b9fb1cd29516