介紹 The BackgroundWorker class allows you to run an operation on a separate, dedicated thread. Time-consuming operations like downloads and database tr ...
介紹
The BackgroundWorker class allows you to run an operation on a separate, dedicated thread. Time-consuming operations like downloads and database transactions can cause your user interface (UI) to seem as though it has stopped responding while they are running. When you want a responsive UI and you are faced with long delays associated with such operations, the BackgroundWorker class provides a convenient solution.
To execute a time-consuming operation in the background, create a BackgroundWorker and listen for events that report the progress of your operation and signal when your operation is finished. You can create the BackgroundWorker programmatically or you can drag it onto your form from the Components tab of the Toolbox. If you create the BackgroundWorker in the Windows Forms Designer, it will appear in the Component Tray, and its properties will be displayed in the Properties window.
To set up for a background operation, add an event handler for the DoWork event. Call your time-consuming operation in this event handler. To start the operation, call RunWorkerAsync. To receive notifications of progress updates, handle the ProgressChanged event. To receive a notification when the operation is completed, handle the RunWorkerCompleted event.
註意:在後臺線程DoWork()中不要出現UI界面里的對象:
You must be careful not to manipulate any user-interface objects in your DoWork event handler. Instead, communicate to the user interface through the ProgressChanged and RunWorkerCompleted events.
BackgroundWorker events are not marshaled across AppDomain boundaries. Do not use a BackgroundWorker component to perform multithreaded operations in more than one AppDomain.
關於參數的傳遞
If your background operation requires a parameter, call RunWorkerAsync with your parameter. Inside the DoWork event handler, you can extract the parameter from the DoWorkEventArgs.Argument property.
For more information about BackgroundWorker, see How to: Run an Operation in the Background.
using System; using System.ComponentModel; using System.Windows.Forms; namespace BackgroundWorkerSimple { public partial class Form1 : Form { public Form1() { InitializeComponent();
backgroundWorker1.WorkerReportsProgress = true; // 允許worker彙報狀態 backgroundWorker1.WorkerSupportsCancellation = true; // 允許worker進行取消操作 } private void startAsyncButton_Click(object sender, EventArgs e) { if (backgroundWorker1.IsBusy != true) { // Start the asynchronous operation. backgroundWorker1.RunWorkerAsync(); // 啟動worker,DoWork()內的代碼自動在後臺線程開始運行。 } } private void cancelAsyncButton_Click(object sender, EventArgs e) { if (backgroundWorker1.WorkerSupportsCancellation == true) { // Cancel the asynchronous operation. backgroundWorker1.CancelAsync(); // 執行這命令後,worker.CancellationPending被設置為True } } // This event handler is where the time-consuming work is done. private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { BackgroundWorker worker = sender as BackgroundWorker; for (int i = 1; i <= 10; i++) { if (worker.CancellationPending == true) { e.Cancel = true; // 接收到用戶取消線程操作的命令後,經判斷是否允許取消操作,再由e.Cancel傳出是否執行”取消“操作。 break; } else { // Perform a time consuming operation and report progress. System.Threading.Thread.Sleep(500); worker.ReportProgress(i * 10); // 後臺線程反饋信息給UI界麵線程,會去執行ProgressChanged()里的代碼。 } } } // This event handler updates the progress. private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) { resultLabel.Text = (e.ProgressPercentage.ToString() + "%"); // UI界麵線程的操作,顯示進度、日誌等。 } // This event handler deals with the results of the background operation. private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (e.Cancelled == true) { resultLabel.Text = "Canceled!"; } else if (e.Error != null) { resultLabel.Text = "Error: " + e.Error.Message; } else { // 線程完成後,在這裡顯示。 resultLabel.Text = "Done!"; } } } }
在UI界麵線程運行的代碼:
backgroundWorker1.RunWorkerAsync();
backgroundWorker1.CancelAsync();
backgroundWorker1_ProgressChanged();
backgroundWorker1_RunWorkerCompleted();
在後臺線程運行的代碼:
backgroundWorker1_DoWork();
worker.ReportProgress();
幾個流程:
1 啟動線程
UI界麵線程中,用戶點擊backgroundWorker1.RunWorkerAsync();啟動線程,接著自動啟動後臺線程,執行backgroundWorker1_DoWork();中的代碼。
在後臺線程中執行worker.ReportProgress();則UI界麵線程中會執行backgroundWorker1_ProgressChanged();中的代碼;
後臺線程執行完畢後,UI界麵線程會執行backgroundWorker1_RunWorkerCompleted();
2 取消線程
UI界麵線程中,用戶點擊backgroundWorker1.CancelAsync();發出取消線程的指令;
在後臺線程中backgroundWorker1_DoWork()代碼中執行以下代碼予以響應:
if (worker.CancellationPending == true)
{
e.Cancel = true; // 接收到用戶取消線程操作的命令後,經判斷是否允許取消操作,再由e.Cancel傳出是否執行”取消“操作。
break;
}
UI界麵線程的
backgroundWorker1_RunWorkerCompleted();將會通過參數e.Cancelled執行代碼:
if (e.Cancelled == true)
{
resultLabel.Text = "Canceled!";
}
傳輸參數,用結構體來傳輸:
backgroundWorker1.RunWorkerAsync(struct arg);
在backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)中,將從參數e中獲取傳入的參數
struct inArg = (struct)e.Argument
如下:
private void startBtn_Click(object sender, EventArgs e) { this.backgroundWorker1.RunWorkerAsync(2000); }
把2000當作參數傳入,在DoWork中,用e.Argument獲取到這個參數。
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { // Do not access the form's BackgroundWorker reference directly. // Instead, use the reference provided by the sender parameter. BackgroundWorker bw = sender as BackgroundWorker; // Extract the argument. int arg = (int)e.Argument; // Start the time-consuming operation. e.Result = TimeConsumingOperation(bw, arg); // If the operation was canceled by the user, // set the DoWorkEventArgs.Cancel property to true. if (bw.CancellationPending) { e.Cancel = true; } }
在後臺線程DoWork()中,給e.Result賦值,這個線程執行的結果會傳出到UI界麵線程:
backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
中的e.Result。