最近项目要用到,窗体Form程序要在后台开启几个子线程,负责和其他端进行通信,异步读写,并且来更改UI。在网上查了有Backgroundworker与Thread两种方法。
1.Backgroundworker
BackgroundWorker是微软的在.net Framwork中添加的一个组件,主要对线程的访问提供了一种安全的方式。简单的说就是对Thread的一次封装。
首先介绍一下BackgroundWorker的相关属性和方法:
属性:
WorkerReportsProgress:是否可以报告进度。
WorkerSupportsCancellation:是否允许异步中止。
IsBusy:是否在运行。
CancellationPending:判断BackgroundWorker是否已经异步取消。
方法:
RunWorkerAsync:开始执行任务。触发DoWork事件
ReportProgress:异步提醒,触发ProgressChanged事件,但是这个如果可以使用,必须设置WorkerReportsProgress为True
CancelAsync:取消BackgroundWorker操作。
事件:
DoWork:执行RunWorkerAsync后触发,异步执行的认为。
ProgressChanged:执行ReportProgress时触发,异步获得进度。
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();
}
}
2.Thread
BackgroundWorker就是一个高级控件,方便使用Thread,后者是前者的灵魂或基础
直接使用后者难度稍大,但换来的是灵活方便。
Thread的使用就比较麻烦了,对于尤其是对异步提醒来说,需要写委托,代码量是很多,但是对于BackgroundWorker来说,却没有线程暂停和继续的方法。但是对于一般的来说,这些功能也是不用的,而且在微软的文档中还提到了,Thread的Resume和Suspend已经不推荐使用。
一个简单的例子:
using System;
using System.Threading;
namespace ThreadsComm
{
public delegate void ReadParamEventHandler(string sParam);
class MyThread
{
public Thread thread1;
private static ReadParamEventHandler OnReadParamEvent;
public MyThread()
{
thread1 = new Thread(new ThreadStart(MyRead));
thread1.IsBackground = true;
thread1.Start();
}
public event ReadParamEventHandler ReadParam
{
add { OnReadParamEvent += new ReadParamEventHandler(value);}
remove{ OnReadParamEvent -= new ReadParamEventHandler(value);}
}
protected void MyRead()
{
int i = 0;
while (true)
{
Thread.Sleep(1000);
i = i + 1;
OnReadParamEvent(i.ToString());//触发事件
}
}
}
}
using System;
using System.Windows.Forms;
namespace ThreadsComm
{
public partial class Form1 : Form
{
private static string param = "";
public Form1()
{
InitializeComponent();
MyThread thread1 = new MyThread();
thread1.ReadParam += this.OnRead;
}
private void OnRead(string sParam)
{
param = sParam;
Object[] list = { this,System.EventArgs.Empty};
this.lblShow.BeginInvoke(new EventHandler(LabelShow), list);
}
protected void LabelShow(Object o, EventArgs e)
{
this.lblShow.Text = param;
}
}
}
3.总结
当你执行的任务较简单,不需要复杂控制时使用BackgroundWorker,较为方便;当你要执行的任务需要复杂控制(如线程同步)时,要自己 创建线程。毕竟,如果我们要实用多个线程,还需要往窗体中加好几个BackgroundWorker控件。
例子
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace UpdateUI
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
backgroundWorker1.DoWork += new DoWorkEventHandler(BW_Work);
backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(BW_Completed);
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(BW_ProgressChanged);
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;
}
//工作事件
protected void BW_Work(object sender,DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
if (worker.CancellationPending)
{
e.Cancel = true;
}
int n = (int)e.Argument;
e.Result = CaculateNumber(n,worker,e);
}
public long CaculateNumber(int n,BackgroundWorker workder,DoWorkEventArgs e)
{
long result = 0;
for(int i=0;i<=n;i++)
{
if (workder.CancellationPending)
{
e.Cancel = true;
}
else
{
int percent = (int)((float)i / (float)n * 100);
Thread.Sleep(500);
workder.ReportProgress(percent);
result++;
}
}
return result;
}
//完成事件
protected void BW_Completed(object sender,RunWorkerCompletedEventArgs e)
{
//可以设置e.Result来传值给该事件
if (e.Error!=null)
{
this.lblBWMessage.Text = e.Error.Message;
}
else if (e.Cancelled)
{
this.lblBWMessage.Text = "Cancel!";
}
else
{
this.lblBWMessage.Text = "Completed!";
}
}
//进度改变事件
protected void BW_ProgressChanged(Object sender, ProgressChangedEventArgs e)
{
this.lblBWMessage.Text = e.ProgressPercentage.ToString();
this.pbBW.Value = e.ProgressPercentage;
}
private void btnStartBW_Click(object sender, EventArgs e)
{
int value = (int)this.numericUpDown1.Value;
this.btnStartBW.Enabled = false;
this.btnCancelBW.Enabled = true;
backgroundWorker1.RunWorkerAsync(value);
}
private void btnCancelBW_Click(object sender, EventArgs e)
{
this.btnStartBW.Enabled = true ;
this.btnCancelBW.Enabled = false;
backgroundWorker1.CancelAsync();
}
Thread threadwork;
private void btnStartThread_Click(object sender, EventArgs e)
{
int initValue = (int)numericUpDown1.Value;
this.btnAbortThread.Enabled = true;
this.btnStartThread.Enabled = false;
ParameterizedThreadStart paramThreadStart = new ParameterizedThreadStart(Thread_DoWork);
threadwork = new Thread(paramThreadStart);
threadwork.IsBackground = true;
threadwork.Start(initValue);
}
public void Thread_DoWork(Object value)
{
int number = (int)value;
if (!this.IsDisposed)
{
Action<int> delLabel = (x) => { this.lblThreadMessage.Text = x.ToString(); };
Action<int> delProgressBar = (y) => { this.pbThread.Value = y; };
for (int i = 0; i <= number; i++)
{
this.lblThreadMessage.BeginInvoke(delLabel,i);
this.pbThread.BeginInvoke(delProgressBar,(int)((float)i / (float)number * 100));
Thread.Sleep(500);
}
}
Action del = delegate() { this.lblThreadMessage.Text = "Completed!"; };
this.lblThreadMessage.BeginInvoke(del);
}
private void btnAbortThread_Click(object sender, EventArgs e)
{
if (threadwork.IsAlive)
threadwork.Abort();
this.lblThreadMessage.Text = "Cancel";
this.btnStartThread.Enabled = true;
this.btnAbortThread.Enabled = false;
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
}