三、Thread/ThreadStart下的跨線程操作控件
在一些情況下,Thread/ThreadStart也是有一定市場的,特別在工作線程很多的情況下,顯得尤為突出。事實上,在這種環境下要實現上述 的例子並不難,代碼也沒有增加多少,前提是你必須理解Control.Invoke方法。該方法在MSDN上的解釋是:在擁有此控件的基礎窗口句柄的線 程上執行委托。如果你注意到了第一張圖片顯示的異常信息,你會很快理解這個方法的重大意義。它可以讓工作線程的中委托在主線程中執行 !因此實現上述例子的思路就是,在工作線程中使用委托來執行操作控件的方法,然後用主窗口的Invoke方法調用!為了實現 BackgroundWorker的ProgressChanged和RunWorkerCompleted事件,定義了ReportProcessInfo委托和DoneAfterCompleted委托。主要代碼如下 :
1//實現BackgroundWorker的ProgressChanged事件
2public delegate void ReportProcessInfo(string Info, int iPercent);
3/**/////實現BackgroundWorker的RunWorkerCompleted事件
4public delegate void DoneAfterCompleted(string Info);
5
6//更新ListvIEw和ProgressBar的方法
7 private void UpdateInfoToUser(string info,int percent)
8 {
9 if (InvokeRequired)
10 Invoke(new ReportProcessInfo(UpdateInfoToUser), info, percent);
11 else
12 {
13 lvOutput.Items.Add(new ListVIEwItem(new string[] { System.DateTime.Now.ToLongTimeString(), info })).EnsureVisible();
14 tssbProcess.Value = percent;
15 }
16
17 }
18 //清空源目錄和目標目錄信息,顯示拷貝文件數的方法
19 private void ShowUserFilesCountInfo(string info)
20 {
21 if (InvokeRequired)
22 Invoke(new DoneAfterCompleted(ShowUserFilesCountInfo), info);
23 else
24 {
25 tbSource.Text = string.Empty;
26 tbTargetDir.Text = string.Empty;
27MessageBox.Show(info);
28 }
29
30 }
31//線程函數
32private void CopyFiles(object SourceDir)
33 {
34 DirectoryInfo di = (DirectoryInfo)SourceDir;
35 int icur = 0;
36 foreach (FileInfo fi in di.GetFiles())
37 {
38 icur++;
39 tsslInfo.Text = string.Format("當前正在處理文件:{0}",fi.Name);
40 fi.CopyTo(Path.Combine(targetDir,fi.Name),true);
41 CopyOneFileIsOK(fi.Name,GetPercent(icur,iFileCount));
42 }
43 CopyFilesIsCompleted(string.Format("本次操作共拷貝了{0}個文件!",icur));
44 }
45
運行結果如下:
四、結尾
代碼中的InvokeRequired用於判斷該段代碼是否是在其他線程中委托調用的,如果為真,就需要在本線程中重新創建一個該委托的實例,並 用Invoke方法調用它,讓這段代碼在本線程中調用。
當代碼中需要對多個控件進行操作,最好使用Form的InvokeRequired來判斷,並使用Form的Invoke方法調用新建的委托實例。當只對某個控 件操作時,就可以只用該控件的InvokeRequired和Invoke。比如tbSource,就可用tbSource.InvokeRequired和tbSource.Invoke。