您的位置:首页 > 其它

WPF 由于其他线程拥有此对象,因此调用线程无法对其进行访问

2015-04-22 18:44 246 查看
转自:

http://blog.sina.com.cn/s/blog_962250db0101487n.html

除非已经对WPF体系结构非常熟悉,对多线程开发很了解,不然我们在与WPF打交道的时候经常会遇到这样一个异常:

由于其他线程拥有此对象,因此调用线程无法对其进行访问。(The calling thread cannot access this object because a different thread owns it)

在WPF中,天生拥有两个线程,一个线程用于渲染UI,另一个线程是管理UI(这个我们称之为UI线程)。传说中android的动画效果为什么没有iphone的动画效果好,就是因为iphone的绘制渲染的线程的优先级非常高,只要有关于动画的操作,比如说滑动一个菜单,那么这个动画会被安排到最优先级运行,从而保证动画的流畅。这我没有深入研究,所以可能技术上来说以上描述不是十分正确,但可以按这个方式去理解。大概WPF中也是这样的理念。UI线程创建了那些在XAML或者在c#中定义的控件,并且拥有他们,并且出于对UI的保护,其他线程是不能访问到UI线程里的东西的,如果我们新建一个线程,然后在这个线程里面修改一个在xaml中或者在主线程中定义的Button.Content,那么就会得到这个异常。

在IM开发过程中,使用agsXMPP库的时候,agsXMPP有很多事件,比如XmppClientConnection.OnStateChanged事件,OnError事件等等,我们会用到很多事件处理函数,在这里必须注意一点就是,当这些事件被触发,代码被执行到事件处理函数里面的时候,执行代码的线程往往不是主线程(这里“往往”不知道用的对不对,反正我碰到的都不是在主线程中执行的),也就是说,如果这时在事件处理函数中写这样的代码:button1.content="something",就会抛出由于其他线程拥有此对象,因此调用线程无法对其进行访问异常。我们可以再visual
studio中调试代码时候在看到当前执行代码的是主线程还是其他线程:

如果线程一栏中没有写明是“主线程”,那么当前执行代码的线程就不是主线程。

这个时候,假如我们必须在其他线程中访问控件,怎么办?这就需要通过Dispatcher了。WPF中大多数控件都继承自DispatcherObject,也就拥有Dispatcher属性,这个Dispatatcher具体是什么东西,我就不写了,因为我也不知道,但显浅的来说,它是对他所属的线程进行工作调度的这么一个对象,或者说线程的一个管家,或者中介。你要在一个拥有某个控件的线程的外部(或者说其他线程)访问这个线程的控件,就只能通过这个控件的Dispatcher来处理了,Dispatcher有两个方法:Invoke和BeginInvoke,用来对外开放访问这个Dispatcher所属的线程所拥有的控件的机会。比如我想在其他线程中访问主线程的Button:

private
void OnEventFired(object sender, MouseButtonEventArgs e)

{

btn.Dispatcher.Invoke(new Action(delegate { button1.Content =
"some text"; }));

}

假设OnEventFired正被其他线程执行,代码里面通过btn.Dispatcher的Invoke方法执行一个(匿名的)函数,该函数里面是设置buttton1.content。

Invoke和BeginInvoke前者是即时调用和异步调用
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐