使用 TPL 将程序图标渲染到图像控件
您好,我正在尝试创建一个 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
WPF 对象(源自 DispatcherObject 的任何对象)是线程仿射的——通常它们只能在创建它们的线程上使用。这包括 BitmapImage 对象。如果您在后台线程上创建 BitmapImage,则只能从该后台线程使用它——这意味着 UI 线程在尝试显示位图时将收到错误。
但是,BitmapImage 源自 Freezable。 Freezable 有一个 Freeze 方法,该方法将使实例变为只读。根据 MSDN 上的“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:
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.虽然您正在使用 CurrentSynchronizationContext,但如果可能必须在图标的
Dispatcher
上运行,请尝试一下......建议:为什么不使用
Priority Binding
和Binding.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....Suggestion: Why arent you using
Priority Binding
andBinding.IsAsync
for slow loading images....http://social.msdn.microsoft.com/Forums/en-AU/wpf/thread/b3dc9baa-4cf6-49ed-a316-b9fb1cd29516