使用 TPL 将程序图标渲染到图像控件

发布于 2024-12-08 18:36:07 字数 1204 浏览 1 评论 0原文

您好,我正在尝试创建一个 Interactivity.Behavior 以在后台加载程序的图标。以下是代码,但它给了我调用线程无法访问该对象,因为另一个线程拥有它。

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




            }

        }
    }

Hi i'm trying to create an Interactivity.Behavior to load a program's icon in the background. The following is the code but it gave me The calling thread cannot access this object because a different thread owns it..

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




            }

        }
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦里兽 2024-12-15 18:36:07

WPF 对象(源自 DispatcherObject 的任何对象)是线程仿射的——通常它们只能在创建它们的线程上使用。这包括 BitmapImage 对象。如果您在后台线程上创建 BitmapImage,则只能从该后台线程使用它——这意味着 UI 线程在尝试显示位图时将收到错误。

但是,BitmapImage 源自 Freezable。 Freezable 有一个 Freeze 方法,该方法将使实例变为只读。根据 MSDN 上的“Freezable 对象概述”:

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

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

WPF objects (anything that descends from DispatcherObject) are thread-affine -- normally they can only be used on the thread that created them. This includes BitmapImage objects. If you create the BitmapImage on a background thread, then it can only be used from that background thread -- which means that the UI thread will get an error when it tries to display the bitmap.

However, BitmapImage descends from Freezable. Freezable has a Freeze method that will make the instance read-only. And per the "Freezable Objects Overview" on MSDN:

A frozen Freezable can also be shared across threads, while an unfrozen Freezable cannot.

So if you add a call to bi.Freeze(); just before you return the image from your background task, then you should be able to use the image successfully from your UI thread.

沫雨熙 2024-12-15 18:36:07

虽然您正在使用 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

Although you are using CurrentSynchronizationContext, give it a try if may have to be run on the Dispatcher of the icon....

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

Suggestion: Why arent you using Priority Binding and Binding.IsAsync for slow loading images....

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文