BackgroundWorker is a helper class under the System.ComponentModel namespace that is used to manage worker threads. It provides several important features:
1) "Cancel" flag, you can signal the worker thread to terminate the worker thread without using abort (call the CancelAsync method).
2) Provide standard plan for reporting progress, completion and exit
3) implements the Icomponet interface, allowing it to participate in the Visual Studio designer: can be dragged directly from the toolbox without having to write code for instantiation
4) Do exception handling on worker threads
5) Ability to update Windows Forms controls to answer work progress or completion
where feature 4) and feature 5) two are particularly useful, which makes it unnecessary to use try/catch blocks in worker threads, and updating UI controls does not need to call Control.Invoke anymore.
In fact, BackgroundWorker is working with a thread pool, which means that the Abort method cannot be called on a BackgroundWorker thread.
Well, say a bunch of concepts and see how BackgroundWorker works.
1) First, invoke the RunWorkerAsync method of the BackgroundWorker instance (this assumes the instance named BackgroundWorker1) to open the background thread. BackgroundWorker is very convenient to use, after calling RunWorkerAsync, the program will automatically complete the next work until the background thread completes the task exit, unless the user wants to cancel the background thread or exit unexpectedly.
There are two overloads of the RunWorkerAsync: void RunWorkerAsync () and RunWorkerAsync (object argument). If you do not need to pass in the initial data to the background thread, use the first overload mode, and when the background thread needs the initial data can be used in mode two, but the overload only accepts one parameter, so if there is more than one data need to consider encapsulation into a struct or class.
2) Calling RunWorkerAsync triggers the BackgroundWorker dowork event, and the arguments provided by the RunWorkerAsync (object argument) are also passed to the DoWork delegate method. The delegate method for the DoWork event is in the form "function name (object sender, DoWorkEventArgs e)", such as:
Backgroundworker1_dowork (object sender, DoWorkEventArgs e)
The variable e has two properties: argument and Result,runworkerasync Pass in the parameter argument to the argument property of DoWorkEventArgs E, and the other property results in the save operation result. Both are object types. The results of the operation can be assigned to the result property, which, after the completion of the operation, is passed to the parameter Runworkercompletedeventargs E of the delegate method of the Onrunworkercompleted event, thus bringing the result of the operation to the foreground thread.
The delegate method of the DoWork event mainly completes the background processing. It is important to note that in this delegate method, before processing the data, it is necessary to determine whether the background operation has been requested (such as calling CancelAsync), and if the background operation has been requested, exit the background thread. Determines whether the method to request cancellation of a background thread is cancellationpending.
if (backgroundworker1.cancellationpending)
{
E.cancel=true;
return;
}
The process of sending processing information continuously for the foreground to display processing progress or completion is also done in this delegate. The message is sent by the ReportProgress method of the BackgroundWorker class [if the Workerreportsprogress property of BackgroundWorker is already set to true, otherwise calling the method throws an exception]. ReportProgress also has two overloaded forms: void reportprogress (int percentprogress) and void reportprogress (int percentprogress, Object UserState).
Percentprogress returns the percentage of completed background operations, ranging from 0% to 100%. Because it is a percentage, it is best to have an integer of [0,100] closed interval, which may throw an exception if this range is exceeded (for example, when assigning this data to a progress bar control).
With regard to the userstate parameter, Microsoft is saying that the state object passed to Backgroundworker.runworkerasync (System.Object). I feel it is to send the background processing status to the ProgressChanged event, for the foreground to determine the subsequent operation, of course, the data in the process can be passed through this parameter to the foreground display.
It is important to note that before or after reportprogress sends the message, the background thread should hand over the time slices to allow other threads to complete related operations, such as updates to the main thread UI interface, which could otherwise cause other threads to work or even cause the program to die. The work of handing over time slices can be done using the Thread.Sleep () method, allowing the background thread to temporarily hibernate for a while. The length of sleep can be updated according to the UI thread's required time setting [if it is too short, it may cause the UI thread's update operation to fail], such as Thread.Sleep (100). Of course, if only to hand over the time slice, it can also be set to Thread.Sleep (0).
3) The ReportProgress method triggers the BackgroundWorker progresschanged event. The delegate method of the ProgressChanged event runs in the main thread and is used primarily to feed back information such as processing progress to the main thread [the delegate method of the DoWork event is not responsible for this work]. The delegate method for ProgressChanged is:
"Method Name (object sender, ProgressChangedEventArgs e)", as follows:
Backgroundworker1_progresschanged (object sender, ProgressChangedEventArgs e)
The parameter e contains the reportprogress outgoing percentprogress and userstate[if the second step calls the overloaded form of a reportprogress with only one argument, then E. Userstate is empty].
In this way, backgroundworker the background operation and communicates with the main thread interface until the background task is completed or interrupted.
For a friendly program, when the background work is completed, you should also give the user a hint that the work has been completed. This work can be done by adding code to the BackgroundWorker onrunworkercompleted event or by setting a delegate method for it. The delegate method for the Onrunworkercompleted event is "function name (object sender, Runworkercompletedeventargs e)". The arguments to the delegate method of the DoWork event have been mentioned earlier DoWorkEventArgs E has an attribute of result to hold the result of the operation, and the value of this property is automatically passed to the delegate method of the Onrunworkercompleted event after the background operation is completed. This is passed to the foreground thread for display. It should be noted that the reason for the end of the thread should be judged in this method [background operation/Cancel background operation/Exception error] and E can only be used if background operation is completed successfully. Result, if E. Cancel==true or E. Error!=null cannot use E. result, otherwise an exception of type "System.InvalidOperationException" is thrown.
The BackgroundWorker also provides a CancelAsync method that allows the user to manually terminate the background task, assuming that the Workersupportscancellation property is true.
At this point, about BackgroundWorker introduction of the basic introduction is complete, I hope to bring you help! Here is a small example showing the basic use of the BackgroundWorker class.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465 666768697071727374 |
namespace BackgroundWorkerTest
{
public
partial
class
Form1 : Form
{
public
Form1()
{
InitializeComponent();
backgroundWorker1.WorkerReportsProgress =
true
;
//报告完成进度
backgroundWorker1.WorkerSupportsCancellation =
true
;
//允许用户终止后台线程
}
//开始按钮
private
void
button1_Click(
object
sender, EventArgs e)
{
if
(!backgroundWorker1.IsBusy )
//判断backgroundWorker1是否正在运行异步操作
{
//backgroundWorker1.RunWorkerAsync();
backgroundWorker1.RunWorkerAsync(1000);
//开始执行后台操作
}
}
private
void
backgroundWorker1_DoWork(
object
sender, DoWorkEventArgs e)
{
e.Result = ListNumber(backgroundWorker1, e);
//运算结果保存在e.Result中
}
bool
ListNumber(
object
sender, DoWorkEventArgs e)
{
int
num=(
int
)e.Argument;
//接收传入的参数
for
(
int
i = 1; i <= num; i++)
{
if
(backgroundWorker1.CancellationPending)
//判断是否请求了取消后台操作
{
e.Cancel=
true
;
return
false
;
}
//backgroundWorker1.ReportProgress(i * 100 / num);
backgroundWorker1.ReportProgress(i * 100 / num,i);
//报告完成进度
Thread.Sleep(0);
//后台线程交出时间片
}
return
true
;
}
private
void
backgroundWorker1_ProgressChanged(
object
sender, ProgressChangedEventArgs e)
{
//将完成进度数据传给进度条
progressBar1.Value = e.ProgressPercentage;
label1.Text = e.ProgressPercentage +
"%"
;
//将中间计算结果在ListBox控件中显示出来
listBox1.Items.Add(e.UserState);
}
Private
void
backgroundWorker1_RunWorkerCompleted(
object
sender, RunWorkerCompletedEventArgs e)
{
if
(!e.Cancelled && e.Error==
null
)
{
MessageBox.Show(
"处理完成了吗? "
+ e.Result);
}
else
//如果取消后台线程或发生了异常
{
MessageBox.Show(
"处理完成了吗? false"
);
}
}
//取消按钮
private void
button2_Click(
object
sender, EventArgs e)
{
if
(backgroundWorker1.WorkerSupportsCancellation==
true
)
{
backgroundWorker1.CancelAsync();
//取消后台操作
backgroundWorker1.Dispose();
//释放资源
}
}
}
}
|
Running results such as:
Deep Anatomy of the BackgroundWorker class