C#後臺線程工作時更新界面的一種處理方法

 

  1. 需求:後臺不間斷地進行某種工作,當獲得特定結果時彈出窗體進行提示,而工作繼續進行。那我的第一反應就是,該工作應放到後臺線程中執行,條件滿足時創建/顯示提示窗體就行啦。代碼如下: 
  2. ==========================Work.cs============================== 
  3. using System; 
  4. using System.Collections.Generic; 
  5. using System.Linq; 
  6. using System.Text; 
  7. using System.Threading; 
  8. using System.ComponentModel; 
  9.  
  10. namespace ThreadTest 
  11.     public class Work 
  12.     { 
  13.         Thread thd; 
  14.         private static int count = 0; 
  15.  
  16.         public Work() 
  17.         { 
  18.             thd = new Thread(new ThreadStart(thdDoWork)); 
  19.             thd.Name = "NewThread"
  20.         } 
  21.  
  22.         WarningForm wf;//提示窗體 
  23.         private void thdDoWork()//後臺工作 
  24.         { 
  25.             while (true
  26.             { 
  27.                 if ((count++ % 10) == 0) 
  28.                 { 
  29.                     wf = new WarningForm();//創建並顯示提示窗體 
  30.                     wf.Show();//將窗體顯示爲非模式對話框 
  31.                 } 
  32.                 Thread.Sleep(600); 
  33.             } 
  34.         } 
  35.  
  36.         public void ThdStart() 
  37.         {                         
  38.             thd.Start(); 
  39.         } 
  40.     } 
  41. ==========================Work.cs============================== 
  42. 同時呢,在WarningForm的構造函數中添加: 
  43. Console.WriteLine("WarningForm Created in : " + Thread.CurrentThread.Name); 
  44. 這樣我們就能夠清楚的看到WarningForm是在哪一個線程中被創建顯示的。 
  45. Debug,彈出提示窗口,而且後臺工作沒有停止,但是提示窗口沒有響應,後臺輸出“WarningForm Created in : NewThread”。我分析這是因爲我們把提示窗體顯示爲了非模式的,而後臺線程顯示窗體後繼續執行,並沒有維護對提示窗體界面的響應,因此發生了以上現象。 
  46.  
  47. 那我們把"wf.Show()"改爲"wf.ShowDialog()"再試一下: 
  48. Debug,彈出提示窗口,界面沒有死掉,後臺輸出"WarningForm Created in : NewThread",但是後臺的工作卻停止了。這是因爲ShowDialog()將窗體顯示爲模式的,也就是說該窗體的顯示阻塞掉了當前線程的運行。 
  49.  
  50. 這樣看來,把提示窗體的顯示放到後臺線程中是不行的,那麼,當後臺線程需要顯示窗體時,如何在主線程中捕獲這種消息呢? 
  51. 哈,這位客官運氣真好,BackgroundWorker的ReportProgress(int percentProgress, object userState)方法最適合解決這個問題了。我們可以在主線程中註冊BackgroundWorker的ProgressChanged事件,當BackgroundWorker的對象調用ReportProgress()時,註冊到ProgressChanged事件的方法就會在主線程中執行,對後臺線程的運行沒有任何影響,然後提示窗體是要顯示爲模式的還是非模式的就看情況啦! 
  52. 我們修改Work.cs如下: 
  53. ==========================Work.cs============================== 
  54. using System; 
  55. using System.Collections.Generic; 
  56. using System.Linq; 
  57. using System.Text; 
  58. using System.Threading; 
  59. using System.ComponentModel; 
  60.  
  61. namespace ThreadTest 
  62.     public class Work 
  63.     { 
  64.         public BackgroundWorker bg; 
  65.         private static int count = 0; 
  66.  
  67.         public Work() 
  68.         { 
  69.             bg = new BackgroundWorker(); 
  70.         } 
  71.  
  72.         private void bgDoWork(object sender, DoWorkEventArgs e) 
  73.         { 
  74.             Thread.CurrentThread.Name = "BgWorker";//修改後臺線程的名字 
  75.             while (true
  76.             { 
  77.                 if ((count++ % 10) == 0) 
  78.                     bg.ReportProgress(count);//激活事件 
  79.                 Thread.Sleep(500); 
  80.             } 
  81.         } 
  82.  
  83.         public void BgStart() 
  84.         { 
  85.             bg.WorkerReportsProgress = true
  86.             bg.DoWork += new DoWorkEventHandler(bgDoWork); 
  87.             bg.RunWorkerAsync(); 
  88.         } 
  89.  
  90.  
  91.     } 
  92. ==========================Work.cs============================== 
  93. 同時在Form1.cs中如下編寫: 
  94. ========================Form1.cs片段============================ 
  95.         WarningForm wf; 
  96.         public Form1() 
  97.         { 
  98.             InitializeComponent(); 
  99.             Thread.CurrentThread.Name = "MainThread";//修改主線程名字 
  100.         } 
  101.         private void button3_Click(object sender, EventArgs e) 
  102.         { 
  103.             //work爲Work的對象 
  104.             work.bg.ProgressChanged += new ProgressChangedEventHandler(bg_ProgressChanged);//註冊這一事件 
  105.             work.BgStart(); 
  106.         } 
  107.  
  108.         private void bg_ProgressChanged(object sender, ProgressChangedEventArgs e) 
  109.         { 
  110.             //事件發生時顯示提示窗體 
  111.             wf = new WarningForm(); 
  112.             wf.Show(); 
  113.             //wf.ShowDialog(); 
  114.         } 
  115. ========================Form1.cs片段============================ 
  116. Debug,輸出"WarningForm Created in : MainThread",可以看到窗體是在主線程中創建顯示的。而無論提示窗體是模式的還是非模式的,一切均能正常運行,到此,我們就實現了要求的功能哈哈! 
  117.  
  118. 另外,請注意ReportProgress(int percentProgress, object userState),它第二個參數是object類型的,再加上如前所述的特性使得BackgroundWorker與界面進行通信的時非常的方便,我們在更新控件的時候可以用它。而如果使用Thread對象的話,則需要通過委託來調用控件的Invoke或者BeginInvoke方法,麻煩的多。但是我想後者肯定具有一些獨特的優點,目前我還不知道,求指點。。 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章