近来在学习Eugene Agafonov编写的《C#多线程编程实战》(译),做些笔记也顺便分享一下^-^
本实例演示了另一种异步编程的方式,即使用BackgroundWorker组件。借助于该对象,可以将异步代码组织为一系列事件及事件处理器
using System;
using System.Threading;
using System.ComponentModel;
namespace 使用BackgroundWorker组件
{
class Program
{
static void Main(string[] args)
{
var bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
bw.DoWork += Worker_DoWork;
bw.ProgressChanged += Worker_ProgressChanged;
bw.RunWorkerCompleted += Worker_Completed;
bw.RunWorkerAsync();
Console.WriteLine("Press C to cancel work");
do
{
if (Console.ReadKey(true).KeyChar=='C')
{
bw.CancelAsync();
}
} while (bw.IsBusy);
}
static void Worker_DoWork(object sender,DoWorkEventArgs e)
{
Console.WriteLine("DoWork thread pool thread id: {0}", Thread.CurrentThread.ManagedThreadId);
var bw = (BackgroundWorker)sender;
for (int i = 1; i <= 100; i++)
{
if (bw.CancellationPending)
{
e.Cancel = true;
return;
}
if (i%10 == 0)
{
bw.ReportProgress(i);
}
Thread.Sleep(TimeSpan.FromSeconds(0.1));
}
e.Result = 42;
}
static void Worker_ProgressChanged(object sender,ProgressChangedEventArgs e)
{
Console.WriteLine("{0}% completed.Progress thread pool thread id:{1}", e.ProgressPercentage, Thread.CurrentThread.ManagedThreadId);
}
static void Worker_Completed(object sender,RunWorkerCompletedEventArgs e)
{
Console.WriteLine("Completed thread pool thread id: {0}", Thread.CurrentThread.ManagedThreadId);
if (e.Error !=null)
{
Console.WriteLine("Exception {0} has occured.", e.Error.Message);
}
else if(e.Cancelled)
{
Console.WriteLine("Operation has been canceled.");
}
else
{
Console.WriteLine("The answer is: {0}", e.Result);
}
}
}
}
程序运行结果如下:
当程序启动时,创建了一个BackgroundWorker组件的实例。显式地指出该后台工作线程支持取消操作及该操作进度的通知。
之后我们使用了事件机制,订阅了三个事件,事件的具体用法不予赘述,当这些事件发生时,将调用相应的事件处理器。
我们一共定义了三个事件。第一个是oWork事件,当一个后台工作对象通过RunWorkerAsync方法启动一个异步操作时,该事件处理器将被调用。该事件处理器将会运行在线程池中。如果需要取消操作,则这里是主要的操作点来取消执行。同时也可以提供该操作的运行进程信息。最后,得到结果后,将结果设置给事件参数,然后RunWorkerCompleted事件处理器将被调用。在该方法中,可以知道操作是成功完成,还是发生错误还是被取消。
基于此,BackgroundWorker组件实际上被使用于Windows窗体应用程序中。该实现通过后台工作事件处理器的代码可以直接与UI控制器交互。与线程池中的线程与UI控制器交互的方式相比较,使用BackgroundWorker组件的方式更加自然和好用。