private delegate void delUpdateControl(Control ctrl, string str);
//--- a delegate---
private delUpdateControl myDelegate;
Finally, create a thread for the PrintTime()method in the Form1_Loadevent handler and start it:
private void Form1_Load(object sender, EventArgs e) {
//...
//...
myDelegate = new delUpdateControl(updateLabel);
Thread t = new Thread(PrintTime);
t.Start();
}
That's it! When you run the application, the time is displayed and updated every second on the Labelcontrol (see Figure 10-11). At the same time, you can move the form, resize it, and so forth, and it is still responsive.
Figure 10-11
Using the BackgroundWorker Control
Because threading is such a common programming task in Windows programming, Microsoft has provided a convenient solution to implementing threading: the BackgroundWorkercontrol for Windows applications. The BackgroundWorkercontrol enables you to run a long background task such as network access, file access, and so forth and receive continual feedback on the progress of the task. It runs on a separate thread.
This section creates a simple Windows application that will show you how the BackgroundWorkercomponent can help make your applications more responsive.
First, start Visual Studio 2008 and create a new Windows application. Populate the default Windows form with the following controls (see Figure 10-12).
Figure 10-12
| Control |
Name |
Text |
Label |
|
Number |
Label |
lblResult |
label2 |
Label |
|
Progress |
TextBox |
txtNum |
|
Button |
btnStart |
Start |
Button |
btnCancel |
Cancel |
ProgressBar |
ProgressBar1 |
|
Drag and drop the BackgroundWorkercomponent from the Toolboxonto the form.
The BackgroundWorkeris a nonvisual control, so it appears below the form in the component section (see Figure 10-13).
Figure 10-13
Right-click on the BackgroundWorkercomponent, and select Properties. Set the WorkerReportsProgressand WorkerSupportsCancellationproperties to Trueso that the component can report on the progress of the thread as well as be aborted halfway through the thread (see Figure 10-14).
Figure 10-14
Here is how the application works. The user enters a number in the TextBoxcontrol ( txtNum) and clicks the Start button. The application then sums all of the numbers from 0 to that number. The progress bar at the bottom of the page displays the progress of the summation. The speed in which the progress bar updates is dependent upon the number entered. For small numbers, the progress bar fills up very quickly. To really see the effect of how summation works in a background thread, try a large number and watch the progress bar update itself. Notice that the window is still responsive while the summation is underway. To abort the summation process, click the Cancel button. Once the summation is done, the result is printed on the Labelcontrol ( lblResult).
Switch to the code behind of the Windows form to do the coding. When the Start button is clicked, you first initialize some of the controls on the form. You then get the BackgroundWorkercomponent to spin off a separate thread by using the RunWorkAsync()method. You pass the number entered by the user as the parameter for this method:
private void btnStart_Click(object sender, EventArgs e) {
lblResult.Text = string.Empty;
btnCancel.Enabled = true;
btnStart.Enabled = false;
progressBar1.Value = 0;
backgroundWorker1.RunWorkerAsync(txtNum.Text);
}
Now, double-click the BackgroundWorkercontrol in design view to create the event handler for its DoWorkevent.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {
BackgroundWorker worker = (BackgroundWorker)sender;
e.Result = SumNumbers(double.Parse(e.Argument.ToString()), worker, e);
}
The DoWorkevent of the BackgroundWorkercomponent invokes the SumNumbers()function (which you will define next) in a separate thread. This event is fired when you call the RunWorkerAsync()method (as was done in the previous step).
The DoWork event handler runs on a separate thread from the UI. Be sure not to manipulate any Windows Forms controls created on the UI thread from this method.
The SumNumbers()function basically sums up all the numbers from 0 to the number specified:
private double SumNumbers(
double number, BackgroundWorker worker, DoWorkEventArgs e) {
int lastPercent = 0;
double sum = 0;
for (double i = 0; i <= number; i++) {
//---check if user cancelled the process---
if (worker.CancellationPending) {
e.Cancel = true;
} else {
sum += i;
if (i % 10 == 0) {
int percentDone = (int)((i / number) * 100);
//---update the progress bar if there is a change---
if (percentDone > lastPercent) {
worker.ReportProgress(percentDone);
lastPercent = percentDone;
}
}
}
}
return sum;
}
It takes in three arguments — the number to sum up to, the BackgroundWorkercomponent, and the DoWorkEventArgs. Within the Forloop, you check to see if the user has clicked the Cancel button (this event is defined a little later in this chapter) by checking the value of the CancellationPendingproperty. If the user has canceled the process, set e.Cancelto True. After every 10 iterations, you calculate the progress completed so far. If there is progress (when the current progress percentage is greater than the last one recorded), you update the progress bar by calling the ReportProgress()method of the BackgroundWorkercomponent. Do not call the ReportProgress()method unnecessarily because frequent calls to update the progress bar will freeze the UI of your application.
Читать дальше