在某些情境下(特別是工作執行緒眾多時),Thread/ThreadStart 仍具優勢。要在這類環境實現跨執行緒操作 UI 並不困難,代碼量也不會大幅增加,前提是你必須理解 Control.Invoke 方法。MSDN 說明:在擁有該控制項基礎視窗控制代碼的執行緒上執行委派。若留意第一張圖片的例外訊息,即可快速理解此方法的關鍵意義——它能讓工作執行緒中的委派在主執行緒中執行!因此實作思路是:在工作執行緒中使用委派來執行操作控制項的方法,再透過主視窗的 Invoke 方法調用。為實現 BackgroundWorker 的 ProgressChanged 與 RunWorkerCompleted 事件,定義了 ReportProcessInfo 與 DoneAfterCompleted 兩個委派。主要代碼如下:
// 實現 BackgroundWorker 的 ProgressChanged 事件
public delegate void ReportProcessInfo(string Info, int iPercent);
/// 實現 BackgroundWorker 的 RunWorkerCompleted 事件
public delegate void DoneAfterCompleted(string Info);
// 更新 ListView 與 ProgressBar 的方法
private void UpdateInfoToUser(string info, int percent)
{
if (InvokeRequired)
Invoke(new ReportProcessInfo(UpdateInfoToUser), info, percent);
else
{
lvOutput.Items.Add(new ListViewItem(new string[] { System.DateTime.Now.ToLongTimeString(), info })).EnsureVisible();
tssbProcess.Value = percent;
}
}
// 清空來源/目標目錄資訊,顯示複製檔案數的方法
private void ShowUserFilesCountInfo(string info)
{
if (InvokeRequired)
Invoke(new DoneAfterCompleted(ShowUserFilesCountInfo), info);
else
{
tbSource.Text = string.Empty;
tbTargetDir.Text = string.Empty;
MessageBox.Show(info);
}
}
// 執行緒函數
private void CopyFiles(object SourceDir)
{
DirectoryInfo di = (DirectoryInfo)SourceDir;
int icur = 0;
foreach (FileInfo fi in di.GetFiles())
{
icur++;
tsslInfo.Text = string.Format("目前正在處理檔案:{0}", fi.Name);
fi.CopyTo(Path.Combine(targetDir, fi.Name), true);
CopyOneFileIsOK(fi.Name, GetPercent(icur, iFileCount));
}
CopyFilesIsCompleted(string.Format("本次操作共複製了 {0} 個檔案!", icur));
}
執行結果如下:

代碼中的 InvokeRequired 用於判斷該段代碼是否在其他執行緒中透過委派調用;若為真,需在主執行緒中重新建立委派實例,並用 Invoke 方法調用,使代碼在主執行緒執行。
當需操作多個控制項時,建議使用 Form 的 InvokeRequired 判斷,並呼叫 Form 的 Invoke 方法調用新建的委派實例。若僅操作單一控制項(如 tbSource),則可直接使用該控制項的 InvokeRequired 與 Invoke。