private delegate void delUpdateControl(Control ctrl, string str);
//--- a delegate---
private delUpdateControl myDelegate;
Finally, create a thread for the PrintTime()
method in the Form1_Load
event 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 Label
control (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 BackgroundWorker
control for Windows applications. The BackgroundWorker
control 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 BackgroundWorker
component 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 BackgroundWorker
component from the Toolbox
onto the form.
The BackgroundWorker
is a nonvisual control, so it appears below the form in the component section (see Figure 10-13).
Figure 10-13
Right-click on the BackgroundWorker
component, and select Properties. Set the WorkerReportsProgress
and WorkerSupportsCancellation
properties to True
so 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 TextBox
control ( 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 Label
control ( 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 BackgroundWorker
component 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 BackgroundWorker
control in design view to create the event handler for its DoWork
event.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {
BackgroundWorker worker = (BackgroundWorker)sender;
e.Result = SumNumbers(double.Parse(e.Argument.ToString()), worker, e);
}
The DoWork
event of the BackgroundWorker
component 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 BackgroundWorker
component, and the DoWorkEventArgs
. Within the For
loop, 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 CancellationPending
property. If the user has canceled the process, set e.Cancel
to 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 BackgroundWorker
component. Do not call the ReportProgress()
method unnecessarily because frequent calls to update the progress bar will freeze the UI of your application.
Читать дальше