BackgroundWorker类可以简化线程在后台执行任务的工作,它具有以下几种主要成员:
属性:WorkReportsProgress,WorkerSupportsCancellation,IsBusy;方法: RunWorkerAsync( ),CancellAsync( ),ReportProgress( );事件:DoWork,ProgressChanged,RunWorkerCompleted;这几种主要成员。
WorkReportsProgress以及WorkerSupportsCancellation属性用于设置是否后台任务可以把进度汇报给主线程以及是否支持从主线程取消;IsBusy属性用来检查是否正在运行后台任务。
3种事件用于发送不同的程序事件和状态;后台线程开始时触发Dowork事件,后台任务汇报状态的时候触发ProgressChanged事件,后台工作线程退出的时候触发RunWorkerCompleted事件。
3种方法用于初始化行为或改变状态;调用RunWorkerAsync方法获取后台线程并且执行DoWork事件处理程序;调用CancelAsync方法把CancellationPending属性设置为True,虽不是必要的,但潜在的取消了线程,DoWork事件处理程序需要检查这个属性来决定是否应该停止处理;DoWork事件处理程序,在后台线程中如果希望向主线程汇报进度时,调用ReportProgress方法。
这些事件处理程序的委托如下:每一个任务都有一个Object对象的引用作为第一个参数,以及EventArgs类的特定子类作为第二个参数。
voidDoWorkEventHandler (object sender, DoWorkEventArgs e)
voidProgressChangeEventHandler(object sender, ProgressChangeEventArgs e)
voidRunWorkerCompletedEventHandler(object sender, RunWorkerCompletedEventArgs e)
当为这些事件写附加事件处理程序时,应该如下来使用这些类。
从创建BackgroundWorker类的对象并对它进行配置开始,如果希望工作线程为主线程汇报进度,需要把WorkReportsProgress属性设置为ture;如果希望从主线程取消工作线程,就把WorkerSupportsCancellation属性设置为true。
设置好属性后,就可以通过调用RunWorkerAsync方法来启动它,它会开一个后台线程并发起DoWork事件处理后台程序。
在主线程中,如果你已启用了WorkerSupportsCancellation属性,然后可以调用CancelAsync方法,它会设置CancellationPending的属性为true,我们需要在后台线程DoWork事件处理代码中检测这个属性。
在后台线程继续执行任务时,要做以下几件事情:
如果WorkReportsProgress属性为true并且后台线程要为主程序汇报进度的话,必须调用BackgroundWorker对象的ReportProgress方法,这时会触发主线程的ProgressChanged事件,从而运行相应的事件处理程序。
如果WorkerSupportsCancellation属性为true,DoWork事件处理代码应该时时检测CancellationPending属性来确定是否已经取消,若是的话应该退出后台线程。
如果后台线程没有取消,完成了其处理程序,则可以通过设置DoWorkEventArgs参数的Result字段来返回结果给主线程。
在后台线程退出的时候会触发RunWorkerCompleted事件,其事件处理程序会在主线程上执行。RunWorkerCompletedEventArgs参数可以包含已完成后台线程的一些信息,比如返回值以及线程是否被取消了。
代码实现如下:
1 using System;
2 using System.Collections.Generic;
3 using System.Threading;
4 using System.Linq;
5 using System.Text;
6 using System.ComponentModel;
7
8 //线程实现原理
9 namespace ConsoleApplication2
10 {
11 class DoBackgroundwork
12 {
13 BackgroundWorker bgWorker = new BackgroundWorker();
14 public long BackgroundTotal {get; private set;}
15 public bool CompletedNormally {get; private set;}
16
17 //构造方法
18 public DoBackgroundwork()
19 {
20 //设置BackgroundWorker属性
21 bgWorker.WorkerReportsProgress = true;
22 bgWorker.WorkerSupportsCancellation = true;
23
24 //把处理程序连接到BackgroundWorker对象
25 bgWorker.DoWork += DoWork_Handler;
26 bgWorker.ProgressChanged += ProgressChanged_Handler;
27 bgWorker.RunWorkerCompleted += RunWorkerCompleted_Handler;
28 }
29 public void StartWorker()
30 {
31 if(!bgWorker.IsBusy)
32 {
33 bgWorker.RunWorkerAsync();
34 }
35 }
36
37 public static long CalculateTheSequence(long value)
38 {
39 long total = 0;
40 for(int i = 0; i < value; ++i)
41 {
42 total += i;
43 }
44 return total;
45 }
46 public void DoWork_Handler(object sender, DoWorkEventArgs args)
47 {
48 BackgroundWorker worker = sender as BackgroundWorker;
49 long total = 0;
50 for(int i = 0; i <= 5; ++i)
51 {
52 if(worker.CancellationPending)
53 {
54 args.Cancel = true;
55 worker.ReportProgress(-1);
56 break;
57 }
58 else
59 {
60 total += CalculateTheSequence(i * 10000000);
61 worker.ReportProgress(i * 20);
62 Thread.Sleep(300);
63 }
64 }
65 args.Result = total;
66 }
67 private void ProgressChanged_Handler(object sender, ProgressChangedEventArgs args)
68 {
69 string output = args.ProgressPercentage == -1
70 ? " Cancelled"
71 : string.Format(" {0}%", args.ProgressPercentage);
72 System.Console.WriteLine(output);
73 }
74 private void RunWorkerCompleted_Handler(object sender, RunWorkerCompletedEventArgs args)
75 {
76 CompletedNormally = !args.Cancelled;
77 BackgroundTotal = args.Cancelled ? 0 : (long)args.Result;
78 }
79 public void Cancel()
80 {
81 if(bgWorker.IsBusy)
82 {
83 bgWorker.CancelAsync();
84 }
85 }
86 }
87 class Program
88 {
89 static void Main(string[] args)
90 {
91 GiveInstructionsToTheUser();
92 OutputTheSummaryHeaders();
93 DoBackgroundwork bgw = new DoBackgroundwork();
94 bgw.StartWorker();
95 long mainTotal = 0;
96 for (int i = 0; i < 5; ++i)
97 {
98 if (Program.CheckForCancelInput())
99 {
100 bgw.Cancel();
101 }
102 mainTotal += DoBackgroundwork.CalculateTheSequence(100000000);
103 Thread.Sleep(200);
104 System.Console.WriteLine(" {0}%", (i + 1) * 20);
105 }
106 SummarizeResults(bgw, mainTotal);
107 System.Console.ReadLine();
108 }
109 private static void GiveInstructionsToTheUser()
110 {
111 System.Console.WriteLine("Press <Enter> to start.");
112 System.Console.ReadLine();
113 }
114 private static void OutputTheSummaryHeaders()
115 {
116 System.Console.WriteLine(" Main Background ");
117 System.Console.WriteLine("---------------------");
118 }
119 private static void SummarizeResults(DoBackgroundwork bgw, long mainTotal)
120 {
121 if (bgw.CompletedNormally)
122 {
123 System.Console.WriteLine("\nBackground Completed Normally");
124 System.Console.WriteLine("Background Total = {0}.", bgw.BackgroundTotal);
125 }
126 else
127 {
128 System.Console.WriteLine("\nBackground Cancelled.");
129 }
130 System.Console.WriteLine("Main Total ={0}.", mainTotal);
131 }
132 private static bool CheckForCancelInput()
133 {
134 bool doCancel = Console.KeyAvailable;
135 if (doCancel)
136 {
137 Console.ReadKey();
138 }
139 return doCancel;
140 }
141 }
142 }