程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#利用委托跨線程更新UI數據

C#利用委托跨線程更新UI數據

編輯:C#入門知識

  在使用C#的過程中,難免會用到多線程,而用多線程之後,線程如何與界面交互則是一個非常頭疼的問題。其實不僅僅是界面,一般情況下,我們往往需要獲得線程的一些信息來確定線程的狀態。比較好的方式是用委托實現,看例子:
         注:本例利用委托和跨線程訪問技術,用界面上的兩個label控件實時顯示線程的執行次數。網上雖然有很多這方面的文章,但是過於簡略,說明很少,剛剛接觸這方面的程序員很難理解,故寫此文。
 
TestClass類:

1. class TestClass 
2. { 
3.         //聲明一個delegate(委托)類型:testDelegate,該類型可以搭載返回值為空,參數只有一個(long型)的方法。 
4.         public delegate void testDelegate(long i); 
5.  
6.         //聲明一個testDelegate類型的對象。該對象代表了返回值為空,參數只有一個(long型)的方法。它可以搭載N個方法。 
7.         public testDelegate mainThread; 
8.  
9.         /// <summary> 
10.         /// 測試方法 
11.         /// </summary> 
12.         public void testFunction()  
13.         { 
14.             long i = 0; 
15.             while(true) 
16.             { 
17.                 i++; 
18.                 mainThread(i); //調用委托對象 
19.                 Thread.Sleep(1000);  //線程等待1000毫秒 
20.             } 
21.         } 
22. } 

winform界面代碼:

1. /// <summary> 
2. /// 按鈕單擊事件 
3. /// </summary> 
4. /// <param name="sender"></param> 
5. /// <param name="e"></param> 
6. private void button1_Click(object sender, EventArgs e) 
7. { 
8.     //創建TestClass類的對象 
9.     TestClass testclass = new TestClass(); 
10.  
11.     //在testclass對象的mainThread(委托)對象上搭載兩個方法,在線程中調用mainThread對象時相當於調用了這兩個方法。 
12.     testclass.mainThread = new TestClass.testDelegate(refreshLabMessage1); 
13.     testclass.mainThread += new TestClass.testDelegate(refreshLabMessage2); 
14.  
15.     //創建一個無參數的線程,這個線程執行TestClass類中的testFunction方法。 
16.     Thread testclassThread = new Thread(new ThreadStart(testclass.testFunction)); 
17.     //啟動線程,啟動之後線程才開始執行 
18.     testclassThread.Start(); 
19. } 
20.  
21. /// <summary> 
22. /// 在界面上更新線程執行次數 
23. /// </summary> 
24. /// <param name="i"></param> 
25. private void refreshLabMessage1(long i)  
26. { 
27.     //判斷該方法是否被主線程調用,也就是創建labMessage1控件的線程,當控件的InvokeRequired屬性為ture時,說明是被主線程以外的線程調用。如果不加判斷,會造成異常 
28.     if (this.labMessage1.InvokeRequired) 
29.     { 
30.         //再次創建一個TestClass類的對象 
31.         TestClass testclass = new TestClass(); 
32.         //為新對象的mainThread對象搭載方法 
33.         testclass.mainThread = new TestClass.testDelegate(refreshLabMessage1); 
34.         //this指窗體,在這調用窗體的Invoke方法,也就是用窗體的創建線程來執行mainThread對象委托的方法,再加上需要的參數(i) 
35.         this.Invoke(testclass.mainThread,new object[] {i}); 
36.     } 
37.     else 
38.     { 
39.         labMessage1.Text = i.ToString(); 
40.     } 
41. } 
42.  
43. /// <summary> 
44. /// 在界面上更新線程執行次數 
45. /// </summary> 
46. /// <param name="i"></param> 
47. private void refreshLabMessage2(long i) 
48. { 
49.     //同上 
50.     if (this.labMessage2.InvokeRequired) 
51.     { 
52.         //再次創建一個TestClass類的對象 
53.         TestClass testclass = new TestClass(); 
54.         //為新對象的mainThread對象搭載方法 
55.         testclass.mainThread = new TestClass.testDelegate(refreshLabMessage2); 
56.         //this指窗體,在這調用窗體的Invoke方法,也就是用窗體的創建線程來執行mainThread對象委托的方法,再加上需要的參數(i) 
57.         this.Invoke(testclass.mainThread, new object[] { i }); 
58.     } 
59.     else 
60.     { 
61.         labMessage2.Text = i.ToString(); 
62.     } 
63. } 
執行效果:

 

 

 

 

說明:

為了便於大家理解,我寫了很詳細的注釋。在這還要說明一下,因為這裡邊有些“莫名其妙”的地方。

l  如何創建線程就不廢話了,一看就懂。

l  public delegate void testDelegate(long i);這句話是創建了一個委托,名字是testDelegate,指定了委托的類型,什麼返回值啦、什麼參數啦,可以把testDelegate理解為一個類,一個規范;publictestDelegate mainThread;這句話當然就是創建testDelegate類的對象了,真正搭載方法的是mainThread對象,它可以搭載N個方法,順序執行。如何搭載捏?看這句話:testclass.mainThread= new TestClass.testDelegate(refreshLabMessage1);這句話是給testclass對象中的mainThread對象搭載方法,但是後邊的new比較難以理解。大家都知道,new這個關鍵字就是用來創建對象的,剛剛已經提醒大家把委托看成一個類,因此這new的是testDelegate這個委托,而不是TestClass(一定要看清了,如果是new的TestClass,要在TestClass後加括號的,後邊接的是方法,而testDelegate明顯不是方法,因此會報錯)。相當於是在TestClass類中又套了一個類,所以才會這樣寫。refreshLabMessage1當然就是testDelegate類構造方法的參數,用來指明委托哪個方法。最後把實例賦給同類型的mainThread。另外,在此例中mainThread委托了兩個方法,用+=運算符即可,如果想去除某個方法,亦可用-=運算符。www.2cto.com

l  最後需要說明的就是跨線程訪問控件問題。窗體上的控件只允許創建它們的線程訪問,也就是主線程,如果非主線程訪問則會發生異常。我們可以借助於控件的InvokeRequired屬性來判斷該控件目前是否被主線程訪問,如果是,返回false。如果不是,再利用Invoke方法找到主線程,讓主線程執行訪問控件的方法,本例中借助於TestClass類中的mainThread對象,委托了訪問控件的方法refreshLabMessage1,再把mainThread對象傳入運行在主線程上的控件的Invoke方法即可。Invoke方法可以理解為:在哪個控件上調用了Invoke,就用那個控件所在的線程處理委托方法。在本例中用this調用Invoke方法,也就是窗體所在的線程,當然也是控件所在的線程。Invoke的兩個參數分別是:委托、委托的方法需要的參數。

 

作者:yangyuankp

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved