调用线程无法访问此对象,因为另一个线程拥有它[重复]
Posted
技术标签:
【中文标题】调用线程无法访问此对象,因为另一个线程拥有它[重复]【英文标题】:The calling thread cannot access this object because a different thread owns it [duplicate] 【发布时间】:2011-02-13 07:22:57 【问题描述】:为什么我不能在下面的代码中创建 CroppedBitmap?我遇到了一个例外:
调用线程无法访问此对象,因为另一个线程拥有它。
如果我将代码更改为
CroppedBitmap cb = new CroppedBitmap(new WriteableBitmap(bf), new Int32Rect(1, 1, 5, 5));
异常消失了吗?为什么?
代码 1,cb.Freeze()
处的异常:
public MainWindow()
InitializeComponent();
ThreadPool.QueueUserWorkItem((o) =>
//load a large image file
var bf = BitmapFrame.Create(
new Uri("D:\\1172735642.jpg"),
BitmapCreateOptions.None,
BitmapCacheOption.None);
bf.Freeze();
Dispatcher.BeginInvoke(
new Action(() =>
CroppedBitmap cb = new CroppedBitmap(bf, new Int32Rect(1,1,5,5));
cb.Freeze();
//set Image's source to cb....
),
DispatcherPriority.ApplicationIdle);
);
代码 2,有效:
ThreadPool.QueueUserWorkItem((o) =>
var bf = BitmapFrame.Create(
new Uri("D:\\1172740755.jpg"),
BitmapCreateOptions.None,
//BitmapCreateOptions.DelayCreation,
BitmapCacheOption.None);
bf.Freeze();
var wb = new WriteableBitmap(bf);
wb.Freeze();
this.Dispatcher.Invoke(
new Action(() =>
var r = new Int32Rect(1, 1, 5, 5);
CroppedBitmap cb = new CroppedBitmap(wb, r);
cb.Freeze();
//set Image's source to cb....
Image.Source = cb;
),
DispatcherPriority.ApplicationIdle);
);
代码 3,无需 WritableBitmap 即可工作:
ThreadPool.QueueUserWorkItem((o) =>
var bf = BitmapFrame.Create(
new Uri("D:\\1172735642.jpg"),
BitmapCreateOptions.None,
//BitmapCreateOptions.DelayCreation,
BitmapCacheOption.None);
bf.Freeze();
var bf2 = BitmapFrame.Create(bf);
bf2.Freeze();
this.Dispatcher.Invoke(
new Action(() =>
var r = new Int32Rect(1, 1, 5, 5);
BitmapSource cb = new CroppedBitmap(bf2, r);
cb.Freeze();
//set Image's source to cb....
Image.Source = cb;
),
DispatcherPriority.ApplicationIdle);
);
【问题讨论】:
BitmapFrame
闻起来像一个 UI 类,它是在工作线程上创建的,然后在 UI 线程上使用...
【参考方案1】:
以下代码可能会帮助您解决从另一个线程更新 gui 元素的问题:
模块级
delegate void updateCallback(string tekst);
这是更新元素的方法:
private void UpdateElement(string tekst)
if (element.Dispatcher.CheckAccess() == false)
updateCallback uCallBack = new updateCallback(UpdateElement);
this.Dispatcher.Invoke(uCallBack, tekst);
else
//update your element here
【讨论】:
我使用它并得到错误:“无法使用属于与其父 Freezable 不同的线程的 DependencyObject。” 很好的实现。易于使用。【参考方案2】:使用 WPF 时请注意,如果您在一个线程中创建 UI 对象,则无法从另一个线程访问它。您的 UI 对象应该(通常)由 UI 线程创建,然后您需要 UI 线程稍后访问它们。没有其他线程能够访问在 UI 线程上创建的对象。
如果您需要从另一个线程访问 UI 对象,则需要 UI 线程 Dispatcher,然后您可以使用它来调用 UI 线程上的调用。
我已经花了很多时间来解决与此类似的问题 - 相信我.. 看看 this question - 它给了我很多关于这个主题的有用信息。
【讨论】:
但是,在我将代码更改为 CroppedBitmap cb = new CroppedBitmap(new WriteableBitmap(bf), new Int32Rect(1, 1, 5, 5));没有例外。为什么?他们仍然在不同的线程中。 抱歉 - 我不确定。没用过WriteableBitmap。也许文档可以给你一个提示? msdn.microsoft.com/en-us/library/…【参考方案3】:您可以在反射器中查看这些类。 cb.Freeze() 中会出现异常。在
CroppedBitmap cb = new CroppedBitmap(bf, new Int32Rect(1,1,5,5));
case 构造函数做了这样的事情:
this.this.Source = source;
所以源不是在当前线程中创建的,所以会出现异常。 在
new WriteableBitmap(bf)
情况,构造函数与 bf 对象同步,并且在当前线程中创建了新源,因此不会出现异常。 如果您对 In Depth 细节感兴趣,您可以随时使用 Reflector 反射基础库 :)
【讨论】:
我更新了我的代码,请看我的新代码 2,CroppedBitmap cb = new CroppedBitmap(wb, r); wb 现在在不同的线程中,但没有例外。为什么? 没有抛出异常,因为 WriteableBitmap 是为与多个线程一起工作而创建的(它甚至具有锁定和解锁方法)msdn.microsoft.com/en-en/library/… 而 CroppedBitmap - 实际上并不是,起初我认为只有 BitmapFrame 可以'不喜欢从多个线程调用,我错了,CroppedBitmap 不喜欢它:) 我又更新了我的代码,请看我的新代码3,现在我用BitmapFrame替换了WritableBitmap,它仍然有效。 BitmapFrame乍一看好像一样,其实不同的构造函数创建的类不同(BitmapFrame其实是抽象的),bf是BitmapFrameDecode,bf2是BitmapFrameEncode,它们是BitmapFrame派生的内部类,所以一个是支持访问当另一个不是时,来自另一个线程。实际上有些属性有复杂的 getter 会抛出异常,所以如果你对它感兴趣,去去反汇编 :) 谢谢,我会尝试使用反射器跟踪代码,但我不知道如何判断位图类是否支持线程。【参考方案4】:我遇到了同样的问题,并通过使用它的调度程序在 UI 线程中创建我的UIElement
解决了这个问题(可以通过 Application.Current.Dispatcher
访问)。
之前:
public static UIElement CreateUIElement()
UIElement element = new UIElement();
//Initialized the UIElement here
return element;
此代码导致 XamlParseException,因为它是在与 UI 线程不同的线程中调用的。
我的工作解决方案:
public static UIElement CreateUIElement()
UIElement element = null;
Application.Current.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.Normal, new Action(
delegate()
element = new UIElement();
// Initialize your UIElement here
));
return element;
可以在此处找到有关调度程序的更多信息 http://tech.pro/tutorial/800/working-with-the-wpf-dispatcher
祝你好运
【讨论】:
以上是关于调用线程无法访问此对象,因为另一个线程拥有它[重复]的主要内容,如果未能解决你的问题,请参考以下文章