使用TPL将程序图标呈现给图像控件

本文关键字:图像 控件 图标 TPL 程序 使用 | 更新日期: 2023-09-27 18:10:44

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

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


            }
        }
    }

使用TPL将程序图标呈现给图像控件

WPF对象(任何从DispatcherObject派生的对象)都是线程仿射的——通常它们只能在创建它们的线程上使用。这包括BitmapImage对象。如果你在后台线程上创建BitmapImage,那么它只能在后台线程中使用——这意味着UI线程在试图显示位图时将得到一个错误。

然而,BitmapImage继承自Freezable。Freezable有一个Freeze方法,它将使实例只读。根据MSDN上的"可冻结对象概述":

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

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

虽然你正在使用CurrentSynchronizationContext,给它一个尝试,如果可能必须在图标的Dispatcher上运行....

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

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

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