在.Net中进行跨线程的控件操作(上篇:Control.Invoke)
本文的重點在于介紹如何在多線程編程中,從非UI線程上訪問界面中的控件。有過多線程編程經驗的人都知道,當我們在非UI線程上試圖給一個界面中的控件賦值的時候,比如說label的Text屬性,系統會拋出一個下面的異常:
這是由于.Net中的大部分控件的實例都是非線程安全的,如果進行跨線程的訪問,可能會造成臟數據,所以.Net默認禁止這種跨線程的賦值操作。那要如何解決這個問題呢?
既然.Net禁止跨線程的賦值操作,那么需要給控件賦值的非UI線程就只有將這種賦值的請求傳遞給UI線程,最終由UI線程完成賦值的操作。如何傳遞這種請求?幸運的是,Control類提供了一個Invoke方法。這個方法的功能是將Invoke所指定的方法提交到生成這個Control的UI線程上執行,也就是說我們可以通過調用這個Invoke方法,讓UI線程來執行Invoke所指定的方法。 由于Invoke方法是一個public方法,所以所有繼承了Control類的.Net控件都可以調用這個方法。
我們來看一下Invoke方法的聲明:
1: public object Invoke(Delegate method);對于這個Invoke方法,它的參數是一個委托類型,調用的時候指向那個你想讓UI線程執行的方法,它的返回值是這個委托指定的方法的返回值。那么如果我想讓UI線程執行一個帶參數的方法怎么辦呢?別著急,Invoke還有另外一個重載方法:
1: public object Invoke(Delegate method, params object[] args);這個Invoke方法的參數除了委托類型外,還有一個不定長的參數數組,用來傳遞委托類型所指定的方法的參數。
有了這兩個Invoke方法后,我們在非UI線程中,如果需要給界面中的控件進行賦值操作的話,就可以調用控件的Invoke方法,讓Invoke方法去執行給控件進行賦值的操作,這樣一來,實際執行給控件賦值的操作就由UI線程執行了。具體過程請參考下面的例子。
1: private void button1_Click(object sender, EventArgs e) 2: { 3: label1.Text = "開始了"; 4: Thread newThread = new Thread(new ThreadStart(DoWork)); 5: newThread.Start(); 6: } 7:? 8: public delegate void SampleDelegate(int i); 9:? 10: private void DoWork() 11: { 12: for (int i = 0; i < 10; i++) 13: { 14: System.Threading.Thread.Sleep(1000); 15: if (isCancel) 16: { 17: isCancel = false; 18: return; 19: } 20: SampleDelegate dele = new SampleDelegate(UpdateLabel); 21: label1.Invoke(dele, i); 22: } 23: } 24:? 25: private void UpdateLabel(int i) 26: { 27: label1.Text = "當前i的值是:" + i.ToString(); 28: }?
?
在上面的例子中,我啟動了一個新的線程來執行DoWork,然后我在Label1中不停的刷新DoWork方法中的 i 的值,由于DoWork是在非UI線程執行的,這樣我不能直接在DoWork中給Label1.Text賦值,所以,我把賦值操作定義到一個方法UpdateLabel中;然后定義一個委托類型(由于Invoke方法的第一個參數是一個委托類型)并實例化它,讓這個委托的實例指向UpdateLabel方法;最后我在DoWork中調用label1.Invoke方法,把執行UpdateLabel的委托提交到UI線程進行執行。這樣就完成了整個賦值的操作。
總之,Control.Invoke方法實際上并不是委托的執行者,它僅僅是將委托傳遞給UI線程,而UI線程才是最終的委托的執行者。所以大家不要被Invoke這個名稱所誤導,實際上它根本沒有執行Invoke操作,僅僅是做了Transfer操作。
最后,請大家仔細想一想,Invoke操作有沒有什么風險?(提示:Control可是還提供了BeginInvoke方法哦~~)
來源:http://www.cnblogs.com/happinessCodes/archive/2010/07/19/1780964.html
轉載于:https://www.cnblogs.com/gjhjoy/p/3580526.html
總結
以上是生活随笔為你收集整理的在.Net中进行跨线程的控件操作(上篇:Control.Invoke)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 递归函数练习——累乘
- 下一篇: DirectX10一变换(三)