背景介绍:
在做程序的进程中,我们极可能遇到这样的情况:当我们履行1个比较耗时的操作,即界面加载数据量略大的时,在该操作未完成之前再去操作界面,就会出现停止响应的情况,这称为界面假死状态,那1个小圆圈转呀转的,想必大家看着就头疼。固然这是1个非常影响用户体验度的地方。
怎样做出1个能够及时响应的用户界面呢?多线程操作。
引入BackgroundWorker组件:
BackgroundWorker是・net里用来履行多线程任务的控件,它允许编程者在1个单独的线程上履行1些操作。
经常使用方法@H_404_27@
1.RunWorkerAsync 开始履行后台操作。引发 DoWork 事件@H_404_27@
2.CancelAsync 要求取消挂起的后台操作。@H_404_27@
注意:这个方法是将 CancellationPending 属性设置为 true,其实不会终止后台操作。在后台操作中要检查 CancellationPending 属性,来决定是不是要继续履行耗时的操作。@H_404_27@
3.ReportProgress
引发 ProgressChanged 事件。@H_404_27@
经常使用属性@H_404_27@
1.CancellationPending 唆使利用程序是不是已要求取消后台操作。只读属性,默许为 false,当履行了 CancelAsync 方法后,值为 true。@H_404_27@
2.WorkerSupportsCancellation
唆使是不是支持异步取消。要履行 CancelAsync 方法,需要先设置该属性为 true。@H_404_27@
3.WorkerReportsProgress
唆使是不是能报告进度。要履行 ReportProgress 方法,需要先设置该属性为 true。@H_404_27@
经常使用事件@H_404_27@
1.DoWork 调用 RunWorkerAsync 方法时产生。@H_404_27@
2.RunWorkerCompleted
后台操作已完成、被取消或引发异常时产生。@H_404_27@
3.ProgressChanged
调用 ReportProgress 方法时产生。@H_404_27@
注意:在 DoWork 事件处理程序中不操作任何用户界面对象。而应当通过 ProgressChanged 和RunWorkerCompleted 事件与用户界面进行通讯。
如果想在 DoWork 事件处理程序中和用户界面的控件通讯,可在用 ReportProgress 方法。ReportProgress(int percentProgress,object userState),可以传递1个对象。
ProgressChanged 事件可以从参数ProgressChangedEventArgs 类的UserState 属性得到这个信息对象。这个事件也能够实现进度条功能,把任务的进度实时显现给用户。
简单的程序用BackgroundWorker 比 Thread 方便,Thread中和用户界面上的控件通讯比较麻烦,需要用拜托来调用控件的 Invoke 或BeginInvoke 方法,没有 BackgroundWorker 方便。
BackgroundWorker Demo
namespace BackgroundWorkerTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
backgroundWorker1.WorkerReportsProgress = true;//报告完成进度
backgroundWorker1.WorkerSupportsCancellation = true;//允许
用户终止
后台线程
}
//开始按钮
private void button1_Click(object sender,EventArgs e)
{
if (!backgroundWorker1.IsBusy )//判断backgroundWorker1是不是正在运行异步操作
{
//backgroundWorker1.RunWorkerAsync();
backgroundWorker1.RunWorkerAsync(1000);//开始履行
后台操作,
调用DoWork事件
}
}
//DoWork事件声明要履行的耗时操作
private void backgroundWorker1_DoWork(object sender,DoWorkEventArgs e)
{
e.Result = ListNumber(backgroundWorker1,e);//运算结果保存在e.Result中
}
bool ListNumber(object sender,DoWorkEventArgs e)
{
int num=(int)e.Argument;//接收传入的参数
for (int i = 1; i <= num; i++)
{
if (backgroundWorker1.CancellationPending)//判断是不是要求了取消
后台操作
{
e.Cancel=true;
return false;
}
//backgroundWorker1.ReportProgress(i * 100 / num);
backgroundWorker1.ReportProgress(i * 100 / num,i);//报告完成进度
Thread.Sleep(0);//
后台线程交出时间片
}
return true;
}
private void backgroundWorker1_ProgressChanged(object sender,ProgressChangedEventArgs e)
{
//将完成进度数据传给进度条
progressBar1.Value = e.ProgressPercentage;
label1.Text = e.ProgressPercentage + "%";
//将中间计算结果在List
Box控件中
显示出来
list
Box1.Items.Add(e.UserState);
}
Private void backgroundWorker1_RunWorkerCompleted(object sender,RunWorkerCompletedEventArgs e)
{
if (!e.Cancelled && e.Error==null)
{
Message
Box.Show("处理完成了吗? " + e.Result);
}
else//如果取消
后台线程或产生了异常
{
Message
Box.Show("处理完成了吗? false");
}
}
//取消按钮
private void button2_Click(object sender,EventArgs e)
{
if (backgroundWorker1.WorkerSupportsCancellation==true)
{
backgroundWorker1.CancelAsync();//取消
后台操作
backgroundWorker1.Dispose();//释放资源
}
}
}
}
总结:
使用backgroundWorker实现多线程大致的步骤是:
1、
绑定线程,设置属性
2、调用BackgroundWorker的RunWorkerAsync方法(可以传递参数),它将调用DoWork事件
3、声明DoWork事件的拜托方法,在后台履行耗时的操作
4、在耗时操作中判断CancellationPending属性,如果为false则退出
5、如果要向用户界面发送信息,则调用BackgroundWorker的ReportProgress方法,它将调用ProgressChanged事件(可以将改变通过object类型传递)
6、在ProgressChanged事件的响应代码中将改变显现给用户,类似进度条。
7、如果需要取消耗时操作,则调用BackgroundWorker的CancelAsync方法,需要和步骤31起使用
总的来讲就是用backgroundWorker组件来新建1个线程,把耗时的部份放到这个线程中在后台进行处理。这样就不会影响界面的正常使用。举个通俗的例子,在我们打开1个网页的时候,先加载完的总是文字,然后图片在渐渐出现。这就是线程的利用,网页打开的时候先显现出文字,供用户阅读,然后把加载图片放到1个单独的线程中,异步的在后台履行,履行终了后把图片显现出来。
这样就避免了1打开界面就加载大量信息,而酿成的界面假死状态,大大提高了用户体验度。
线程处理这块不熟,希望大家指导。