标签:framework ima red 引入 nbsp 文本 空间 通过 显示
前言:
在处理多线程的问题中,经常会遇到在工作线程中去更新界面显示,比如某个按钮的文本是打开,然后你要点一下,使之文本变为关闭。一开始我会在点击事件中直接改变按钮文本的值,这样做貌似也没什么问题。然而有时候却会报异常,“不能从创建该控件的线程中调用它”。造成这种情况的原因就是控件的创造是在主线程中的,事件响应是在控件的线程中被执行的。这就会造成一个问题:事件响应后去改变控件的状态,而此时主线程正在重绘控件的外观,而你又要改变控件的状态,这就会造成线程之间的冲突,画面的混乱,从而引发异常。
怎么办呢?
如果控件响应也是在主线程就好了。OK,可以使用控件的Invoke方法:它可以将控件的线程在主线程上激活。Invoke方法会顺着控件树向上搜索,直到找到创建空间的那个线程(通常是主线程),然后进入那个线程去改变控件的外观,确保不发生线程冲突。写法如下:
1 void ButtonClick(object sender,EventArgs e) 2 { 3 button.Invoke(new EventHandler(delegate 4 { 5 button.Text="关闭"; 6 })); 7 }
Invoke()方法需要创建一个委托。在C#3.0之后,引入了Lamda表达式,像上面的匿名委托有了更简洁的写法。.NET Framework 3.5以后更是可以使用Action封装方法。如下面所示:
void ButtonClick(object sender,EventArgs e) { this.Invoke(new action(()=> { button.Text="关闭"; })); }
当一个控件的InvokeRequired属性值为真时,说明有一个创建它以外的线程想访问它,此时它会在内部调用new MethodInvoke(LoadGlobalImage)来完成下面的步骤,这样做保证了控件的安全。也就是说用之前先通知一声。
其他
MSDN中说,获取一个值,该值指示调用方在对控件进行方法调用时是否必须调用Invoke方法,因为调用方位于创建控件所在的线程以外的线程中。
如果控件的Handle是在与调用线程不同的线程上创建的(说明必须通过Invoke方法对控件进行调用),则为True;否则为False。
标签:framework ima red 引入 nbsp 文本 空间 通过 显示
原文地址:http://www.cnblogs.com/HoloSherry/p/7764207.html