一、BackgroundWorker组件
在VS2005中添加了BackgroundWorker组件,该组件在多线程编程方面使用起来非常方便,然而在开始时由于没有搞清楚它的使用机制,走了不少的弯路,现在把我在使用它的过程中的经验与诸位分享一下。
BackgroundWorker类中主要用到的有这列属性、方法和事件:
重要属性:
1、CancellationPending
获取一个值,指示应用程序是否已请求取消后台操作。通过在DoWork事件中判断CancellationPending属性可以认定是否需要取消后台操作(也就是结束线程);
2、IsBusy
获取一个值,指示 BackgroundWorker
是否正在运行异步操作。程序中使用IsBusy属性用来确定后台操作是否正在使用中;
3、WorkerReportsProgress
获取或设置一个值,该值指示BackgroundWorker能否报告进度更新
4、WorkerSupportsCancellation 获取或设置一个值,该值指示
BackgroundWorker
是否支持异步取消。设置WorkerSupportsCancellation为true使得程序可以调用CancelAsync方法提交终止挂起的后台操作的请求;
重要方法:
1、CancelAsync
请求取消挂起的后台操作
2、RunWorkerAsync 开始执行后台操作
3、ReportProgress 引发ProgressChanged事件
重要事件:
1、DoWork 调用
RunWorkerAsync
时发生
2、ProgressChanged
调用 ReportProgress
时发生
3、RunWorkerCompleted 当后台操作已完成、被取消或引发异常时发生
另外还有三个重要的参数是RunWorkerCompletedEventArgs以及DoWorkEventArgs、ProgressChangedEventArgs。
BackgroundWorker的各属性、方法、事件的调用机制和顺序:
从上图可见在整个生活周期内发生了3次重要的参数传递过程:
参数传递1:此次的参数传递是将RunWorkerAsync(Object)中的Object传递到DoWork事件的DoWorkEventArgs.Argument,由于在这里只有一个参数可以传递,所以在实际应用往封装一个类,将整个实例化的类作为RunWorkerAsync的Object传递到DoWorkEventArgs.Argument;
参数传递2:此次是将程序运行进度传递给ProgressChanged事件,实际使用中往往使用给方法和事件更新进度条或者日志信息;
参数传递3:在DoWork事件结束之前,将后台线程产生的结果数据赋给DoWorkEventArgs.Result一边在RunWorkerCompleted事件中调用RunWorkerCompletedEventArgs.Result属性取得后台线程产生的结果。
另外可以看到DoWork事件是在后台线程中运行的,所以在该事件中不能够操作用户界面的内容,如果需要更新用户界面,可以使用ProgressChanged事件及RunWorkCompleted事件来实现。
在WinForm中经常遇到一些费时的操作界面,比如统计某个磁盘分区的文件夹或者文件数目,如果分区很大或者文件过多的话,处理不好就会造成“假死”的情况,或者报“线程间操作无效”的异常,为了解决这个问题,可以使用委托来处理,在.net2.0中还可以用BackgroundWorker类。
BackgroundWorker类是.net
2.0里新增加的一个类,对于需要长时间操作而不需要用户长时间等待的情况可以使用这个类。
注意确保在 DoWork
事件处理程序中不操作任何用户界面对象。而应该通过 ProgressChanged 和 RunWorkerCompleted
事件与用户界面进行通信。
public
partial
class
MainWindow :
Window
{
private
BackgroundWorker m_BackgroundWorker;
//
申明后台对象
public
MainWindow()
{
InitializeComponent();
m_BackgroundWorker =
new
BackgroundWorker();
//
实例化后台对象
m_BackgroundWorker.WorkerReportsProgress =
true
;
// 设置可以通告进度
m_BackgroundWorker.WorkerSupportsCancellation =
true
;
// 设置可以取消
m_BackgroundWorker.DoWork +=
new
DoWorkEventHandler(DoWork);
m_BackgroundWorker.ProgressChanged +=
new
ProgressChangedEventHandler(UpdateProgress);
m_BackgroundWorker.RunWorkerCompleted +=
new
RunWorkerCompletedEventHandler(CompletedWork);
m_BackgroundWorker.RunWorkerAsync(
this
);
}
void
DoWork(
object
sender,
DoWorkEventArgs e)
{
BackgroundWorker bw = sender
as
BackgroundWorker;
MainWindow win = e.Argument
as
MainWindow;
int
i =
0;
while
( i <=
100 )
{
if
(bw.CancellationPending)
{
e.Cancel =
true
;
break
;
}
bw.ReportProgress(i++);
Thread.Sleep(1000);
}
}
void
UpdateProgress(
object
sender,
ProgressChangedEventArgs e)
{
int
progress =
e.ProgressPercentage;
label1.Content =
string
.Format(
"{0}"
,progress);
}
void
CompletedWork(
object
sender,
RunWorkerCompletedEventArgs e)
{
if
( e.Error !=
null
)
{
MessageBox.Show(
"Error"
);
}
else
if
(e.Cancelled)
{
MessageBox.Show(
"Canceled"
);
}
else
{
MessageBox.Show(
"Completed"
);
}
}
private
void
button1_Click(
object
sender,
RoutedEventArgs e)
{
m_BackgroundWorker.CancelAsync();
}
}
/// <summary>
/// 创建多线程,
/// </summary>
delegate void MyDeletegate();
private void button3_Click(object
sender, EventArgs e)
{
progressBar1.Visible =
true;
for (int i = 0; i <= 100; i++)
{
progressBar1.Value = i;
System.Threading.Thread.Sleep(50);
if (progressBar1.Value == 100)
{
progressBar1.Visible = false;
}
}
//LoadMoneyOfMonth();
Thread t = new
Thread(ThreadBind);
t.Name = "NewThread";
t.Start();
}
private void ThreadBind()
{
if
(InvokeRequired)
{
//LoadMoneyOfMonth加载数据
BeginInvoke(new
MyDeletegate(LoadMoneyOfMonth));
}
}