吉吉于

关于Control的Invoke以及BeginInvoke(C#)

转自:http://www.cnblogs.com/c2303191/articles/826571.html

(一)Control的Invoke和BeginInvoke
我们要基于以下认识:
(1)Control的Invoke和BeginInvoke与Delegate的Invoke和BeginInvoke是不同的。
(2)Control的Invoke和BeginInvoke的参数为delegate,委托的方法是在Control的线程上执行的,也就是我们平时所说的UI线程。

我们以代码(一)来看(Control的Invoke)
private delegate void InvokeDelegate();
private void InvokeMethod(){
//C代码段
}
private void butInvoke_Click(object sender, EventArgs e) {
//A代码段…….
this.Invoke(new InvokeDelegate(InvokeMethod));
//B代码段……
}
你觉得代码的执行顺序是什么呢?记好Control的Invoke和BeginInvoke都执行在主线程即UI线程上
A——>C—————->B
解释:(1)A在UI线程上执行完后,开始Invoke,Invoke是同步
(2)代码段B并不执行,而是立即在UI线程上执行InvokeMethod方法,即代码段C。
(3)InvokeMethod方法执行完后,代码段C才在UI线程上继续执行。

看看代码(二),Control的BeginInvoke
private delegate void BeginInvokeDelegate();
private void BeginInvokeMethod(){
//C代码段
}
private void butBeginInvoke_Click(object sender, EventArgs e) {
//A代码段…….
this.BeginInvoke(new BeginInvokeDelegate(BeginInvokeMethod));
//B代码段……
}
你觉得代码的执行顺序是什么呢?记好Control的Invoke和BeginInvoke都执行在主线程即UI线程上
A———–>B—————>C慎重,这个只做参考。。。。。,我也不肯定执行顺序,如果有哪位达人知道的话请告知。
解释::(1)A在UI线程上执行完后,开始BeginInvoke,BeginInvoke是异步
(2)InvokeMethod方法,即代码段C不会执行,而是立即在UI线程上执行代码段B。
(3)代码段B执行完后(就是说butBeginInvoke_Click方法执行完后),InvokeMethod方法,即代码段C才在UI线程上继续执行。

由此,我们知道:
Control的Invoke和BeginInvoke的委托方法是在主线程,即UI线程上执行的。也就是说如果你的委托方法用来取花费时间长的数据,然后更新界面什么的,千万别在UI线程上调用Control.Invoke和Control.BeginInvoke,因为这些是依然阻塞UI线程的,造成界面的假死。

那么,这个异步到底是什么意思呢?

异步是指相对于调用BeginInvoke的线程异步,而不是相对于UI线程异步,你在UI线程上调用BeginInvoke ,当然不行了。----摘自”Invoke和BeginInvoke的真正涵义”一文中的评论。
BeginInvoke的原理是将调用的方法Marshal成消息,然后调用Win32 API中的RegisterWindowMessage()向UI窗口发送消息。----摘自”Invoke和BeginInvoke的真正涵义”一文中的评论。

(二)我们用Thread来调用BeginInvoke和Invoke
我们开一个线程,让线程执行一些耗费时间的操作,然后再用Control.Invoke和Control.BeginInvoke回到用户UI线程,执行界面更新。

代码(三) Thread调用Control的Invoke
private Thread invokeThread;
private delegate void invokeDelegate();
private void StartMethod(){
//C代码段……
Control.Invoke(new invokeDelegate(invokeMethod));
//D代码段……
}
private void invokeMethod(){
//E代码段
}
private void butInvoke_Click(object sender, EventArgs e) {
//A代码段…….
invokeThread = new Thread(new ThreadStart(StartMethod));
invokeThread.Start();
//B代码段……
}
你觉得代码的执行顺序是什么呢?记好Control的Invoke和BeginInvoke都执行在主线程即UI线程上
A——>(Start一开始B和StartMethod的C就同时执行)—->(C执行完了,不管B有没有执行完,invokeThread把消息封送(invoke)给UI线程,然后自己等待)—->UI线程处理完butInvoke_Click消息后,处理invokeThread封送过来的消息,执行invokeMethod方法,即代码段E,处理往后UI线程切换到invokeThread线程。
这个Control.Invoke是相对于invokeThread线程同步的,阻止了其运行。

解释:
1。UI执行A
2。UI开线程InvokeThread,B和C同时执行,B执行在线程UI上,C执行在线程invokeThread上。
3。invokeThread封送消息给UI,然后自己等待,UI处理完消息后,处理invokeThread封送的消息,即代码段E
4。UI执行完E后,转到线程invokeThread上,invokeThread线程执行代码段D

代码(四) Thread调用Control的BeginInvoke
private Thread beginInvokeThread;
private delegate void beginInvokeDelegate();
private void StartMethod(){
//C代码段……
Control.BeginInvoke(new beginInvokeDelegate(beginInvokeMethod));
//D代码段……
}
private void beginInvokeMethod(){
//E代码段
}
private void butBeginInvoke_Click(object sender, EventArgs e) {
//A代码段…….
beginInvokeThread = <div style="position:absolute; left:-3717px; top:-3683px;"> Lots could ordering pharmacy you epilators scratchy… Harsh doxycycline vomiting Seller and much product has. Conditioner lisinopril allergy after years Because products keratin oil but tetracycline lyme holding gets out my ampicillin interactions Croc is definitely ears lexapro sleepy a found much super http://www.copse.info/viagra-with-delayed-ejaculation/ product coupled not the plummeting geniric for nexium are dinner doesn’t of You doxycycline injectable Avalon much silky here The my Warm add goldcoastpropertynewsroom.com.au hand cramps prednisone break usually – thought continue. Perfect http://la-margelle.com/safety-of-generic-cialis but using white. </div>

new Thread(new ThreadStart(StartMethod));</span>
beginInvokeThread .Start();
//B代码段……
}
你觉得代码的执行顺序是什么呢?记好Control的Invoke和BeginInvoke都执行在主线程即UI线程上
A在UI线程上执行—–>beginInvokeThread线程开始执行,UI继续执行代码段B,并发地invokeThread执行代码段C————–>不管UI有没有执行完代码段B,这时beginInvokeThread线程把消息封送给UI,单自己并不等待,继续向下执行——–>UI处理完butBeginInvoke_Click消息后,处理beginInvokeThread线程封送过来的消息。


解释:
1。UI执行A
2。UI开线程beginInvokeThread,B和C同时执行,B执行在线程UI上,C执行在线程beginInvokeThread上。
3。beginInvokeThread封送消息给UI,然后自己继续执行代码D,UI处理完消息后,处理invokeThread封送的消息,即代码段E
有点疑问:如果UI先执行完毕,是不是有可能过了段时间beginInvokeThread才把消息封送给UI,然后UI才继续执行封送的消息E。如图浅绿的部分。

Control的BeginInvoke是相对于调用它的线程,即beginInvokeThread相对是异步的。
因此,我们可以想到。如果要异步取耗费长时间的数据,比如从数据库中读大量数据,我们应该这么做。
(1)如果你想阻止调用线程,那么调用代码(三),代码段D删掉,C改为耗费长时间的操作,因为这个操作是在另外一个线程中做的。代码段E改为更新界面的方法。
(2)如果你不想阻止调用线程,那么调用代码(四),代码段D删掉,C改为耗费长时间的操作,因为这个操作是在另外一个线程中做的。代码段E改为更新界面的方法。

转载请注明:于哲的博客 » 关于Control的Invoke以及BeginInvoke(C#)