C#實(shí)現(xiàn)窗體與子線程的交互的方法
本文實(shí)例簡(jiǎn)述了C#實(shí)現(xiàn)窗體與子線程間通訊的方法,對(duì)于C#初學(xué)者有一定的借鑒價(jià)值。具體方法如下:
一般來說窗體上的UI在默認(rèn)情況下不允許使用子線程(或者其它非創(chuàng)建控件的UI線程)去控制(這在NET2.0以下是允許的,但是考慮到安全性等問題,從2.0開始就禁止使用這個(gè)功能,除非Form的CheckForIllegalCrossThreadCalls=true,不推薦這樣使用)。
那么如何實(shí)現(xiàn)C#窗體與子線程的交互呢?具體方法如下:
一、使用Invoke或者BeginInvoke方法:
用一個(gè)線程,里邊調(diào)用Invoke或者BeginInvoke方法即可:
public partial class Form1 : Form { public void Processing(int num) { int answer = 2; Task t = new Task(() => { for (int i = 3; i <= num; i++) { answer *= i; } this.BeginInvoke(new MethodInvoker(() => { Thread.Sleep(3000); MessageBox.Show("Finished!") })); MessageBox.Show("OK"); }); t.Start(); } public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { MessageBox.Show("First!"); Processing(10); } }
這里值得注意:
1)BeginInvoke:這里的“異步”并不是針對(duì)UI線程,而是說當(dāng)Control的BeginInvoke在某個(gè)子線程中調(diào)用時(shí),子線程中BeginInvoke后面的代碼(彈出“Finished”框框)會(huì)先執(zhí)行,然后等到BeginInvoke中的那個(gè)委托方法完全執(zhí)行完畢之后Label才會(huì)被賦值。如果改成Invoke,那么“OK”永遠(yuǎn)在Invoke的委托代碼徹底執(zhí)行完畢之后才被執(zhí)行。
所以BeginInvoke=Invoke(在UI主線程中,所以不建議在主線程中直接這樣調(diào)用)
二、線程同步SynchronizedContext:
public partial class Form1 : Form { public void Processing(int num,SynchronizationContext context) { int answer = 2; Task t = new Task(() => { for (int i = 3; i <= num; i++) { answer *= i; } SynchronizationContext.SetSynchronizationContext(context); SynchronizationContext.Current.Post((obj) => { Thread.Sleep(3000); MessageBox.Show("Finished"); }, null); MessageBox.Show("Last"); }); t.Start(); } public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { MessageBox.Show("First!"); Processing(10,SynchronizationContext.Current); } }
和BeginInvoke、Invoke類似,需要注意:
1)SynchronizationContext:唯獨(dú)在UI窗體線程中會(huì)自動(dòng)初始化(button1_Click事件中SynchronizationContext.Current為當(dāng)前窗體),其它線程與線程要交互,必須通過new SynchronizationContext()實(shí)現(xiàn))。
2)Post方法等同于BeginInvoke作用,Send等同于Invoke作用。
大家如果仔細(xì)實(shí)驗(yàn)代碼,還會(huì)發(fā)現(xiàn)無論何種情況,彈出“Finished”框框總是界面“假死”3秒,是的,證明了以上4個(gè)方法都是在UI線程上執(zhí)行的(只不過是同步或者異步向窗體消息泵發(fā)送信息而已)。所以應(yīng)該“一次性地把數(shù)據(jù)在子線程中先全部處理干凈(在Invoke,BeginInvoke,Send或者Post前得出結(jié)果,寫代碼),然后一次性發(fā)送通知給窗體,更新界面即可)。
此外還需要注意:
任何委托(Delegate)也有BeginInvoke方法,它是真正的異步,一旦Invoke一定是開辟一個(gè)線程去執(zhí)行的。
相關(guān)文章
C#實(shí)現(xiàn)IDisposable接口釋放非托管資源
這篇文章主要為大家介紹了C#實(shí)現(xiàn)IDisposable接口釋放非托管資源,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05C#使用Data?Annotations進(jìn)行手動(dòng)數(shù)據(jù)驗(yàn)證
這篇文章介紹了C#使用Data?Annotations進(jìn)行手動(dòng)數(shù)據(jù)驗(yàn)證的方法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06C# 重寫ComboBox實(shí)現(xiàn)下拉任意組件的方法
C#種的下拉框ComboBox不支持下拉復(fù)選框列表與下拉樹形列表等,系統(tǒng)中需要用到的地方使用了第三方組件,現(xiàn)在需要將第三方組件替換掉。這篇文章主要介紹了C# 重寫ComboBox實(shí)現(xiàn)下拉任意組件的相關(guān)資料,需要的朋友可以參考下2016-10-10C# 添加、修改以及刪除Excel迷你圖表的實(shí)現(xiàn)方法
下面小編就為大家分享一篇C# 添加、修改以及刪除Excel迷你圖表的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2017-12-12