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