在Silverlight中极其耗时的操作会导致UI进程假死,如果将复杂的操作和UI显示分离开而且我们需要了解这复杂操作的后台进程当前运行的进度如何?这里我们可以使用BackgroundWorker来解决这个问题。
BackgroundWorker是一个封装了的Thread组件,它能够让用户方便的开启一个独立的线程执行复杂和耗时的后台工作,随时报告当前完成程 度,随时中止异步线程操作,还可以在异步操作状态报告中(ProgressChanged)和异步操作完成后(RunWorkerCompleted)的 响应事件中访问UI线程。
BackgroundWorker的一些常用的属性、方法和事件如下:
•属性
CancellationPending 获取一个值,指示应用程序是否已请求取消后台操作。
IsBusy 获取一个值,指示 BackgroundWorker 是否正在运行异步操作。
WorkerReportsProgress 获取或设置一个值,该值指示 BackgroundWorker 能否支持报告进度更新。
WorkerSupportsCancellation 获取或设置一个值,该值指示 BackgroundWorker 是否支持异步取消。
•方法
CancelAsync 请求取消挂起的后台操作。
ReportProgress 引发 ProgressChanged 事件。
RunWorkerAsync 开始执行后台操作。
•事件
DoWork 调用 RunWorkerAsync 时发生。
ProgressChanged 调用 ReportProgress 时发生。
RunWorkerCompleted 当后台操作已完成、被取消或引发异常时发生。
现在我们清理一下这个组件的运行思路:
一、首先我们创建一个BackgroundWorker对象实例,然后设置它的属性WorkerReportsProgress、 WorkerSupportsCancellation为ture,为BackgroundWorker实例的DoWork 、 ProgressChanged 、RunWorkerCompleted 三个事件加载相应的事件处理方法。
二、此时按下“运行按钮”,根据BackgroundWorker的IsBusy属性判断当前对象是否已经正在开始执行后台异步线程,如果未执行异步线 程,则调用RunWorkerAsync()方法开始执行异步线程并且可以传递参数A,此时将触发DoWork事件,在这个事件内部是不能直接操作UI线 程的。此时在DoWork响应时间内部首先判断CancellationPending属性是否为ture,如果为true表示当前已经取消异步进程运 行,否则继续运行需要处理的复杂运算,可以通过e.Argument属性接收到参数A。
三、在运行复杂运算的过程中,每隔一个时间段执行一次ReportProgress(int percentProgress)函数,传递当前运行完成百分数,此时为参数B,然后触发ProgressChanged事件,在此事件中通过 e.ProgressPercentage属性接收到参数B,更新UI的ProgressBar控件,显示当前的完成进度。
四、当DoWork内的复杂运算完毕之后为当前DoWork事件的e.Result赋值C,再触发RunWorkerCompleted 事件,此时在RunWorkerCompleted 事件中接受e.Result的值。将结果显示到UI界面上即可。
下面我们来看一段实例程序源码MainPage.xaml.cs,相关的运行注释在代码中已经注明:
- public partial class MainPage : UserControl
- {
- //声明一个BackgroundWorker对象实例
- private BackgroundWorker bgWorker = new BackgroundWorker();
- public MainPage()
- {
- InitializeComponent();
- InitBackGroundWorker();
- }
- //初始化BackgroundWorker的相关属性和加载事件
- public void InitBackGroundWorker()
- {
- //BackgroundWorker是否支持报告执行进度
- bgWorker.WorkerReportsProgress = true;
- //BackgroundWorker是否支持取消运行异步操作
- bgWorker.WorkerSupportsCancellation = true;
- //加载DoWork、ProgressChanged、RunWorkerCompleted事件
- bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
- bgWorker.ProgressChanged += new ProgressChangedEventHandler(bgWorker_ProgressChanged);
- bgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorker_RunWorkerCompleted);
- }
- //后台异步执行操作的地方
- void bgWorker_DoWork(object sender, DoWorkEventArgs e)
- {
- //获取到传递进来的参数
- string str = e.Argument.ToString();
- //执行100次循环
- for (int i = 0; i < 100; i++)
- {
- //判断当前BackgroundWorker是否已经被取消了异步操作
- if (bgWorker.CancellationPending == false)
- {
- //如果没有被取消异步操作,则线程阻塞以下,然后报告给bgWorker_ProgressChanged事件
- Thread.Sleep(50);
- bgWorker.ReportProgress(i + 1);
- e.Result = "3322";
- }
- else
- {
- //设置当前已取消异步线程操作
- e.Cancel = true;
- break;
- }
- }
- }
- //进度改变时触发的事件执行函数,这里显示执行进度
- void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
- {
- //设置当前进度条的值为事件执行完成程度值
- this.progressBar1.Value = e.ProgressPercentage;
- }
- //异步操作执行完毕之后的处理
- void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
- {
- //完成异步操作之后检查是否取消了异步操作,弹出相关提示
- if (e.Cancelled == true)
- {
- MessageBox.Show("取消异步线程操作");
- }
- else
- {
- MessageBox.Show("异步线程执行完毕" + e.Result);
- }
- this.btncancel.Content = "已完成";
- }
- private void btnrun_Click(object sender, RoutedEventArgs e)
- {
- //如果后台进程未开始运行,则开始运行线程
- if (bgWorker.IsBusy != true)
- {
- bgWorker.RunWorkerAsync("我是参数");
- }
- }
- private void btncancel_Click(object sender, RoutedEventArgs e)
- {
- //取消异步操作。
- bgWorker.CancelAsync();
- }
- }
本实例采用VS2010+Silverlight 4.0编写,点击 SLBackgroundWorker_Caleung.rar 下载本实例源码。
本文转自程兴亮 51CTO博客,原文链接:http://blog.51cto.com/chengxingliang/821973