在C#顺序中,常常会有一些耗时较长的CPU密集型运算,假如直接在 UI 线程实行如许的运算就会涌现UI不响应的题目。处置惩罚这类题目的重要门路是运用多线程,启动一个背景线程,把运算操纵放在这个背景线程中完成。然则原生接口的线程操纵有一些难度,假如要更进一步的去完成线程间的通讯就会难上加难。
还好 .NET 类库中供应了一个叫做 BackgroundWorker 的类能够比较文雅的处置惩罚这类题目。虽然BackgroundWorker 类运用起来比较简朴,但个中照样有一些须要注重的细节,下面我们就经由历程 demo 顺序引见它的重要用法。我们在 demo中盘算1到100的累加和,为了演示,每次盘算都 sleep 600毫秒,demo 的UI为:
用法概述
在窗体上构建一个BackgroundWorker 实例,在它的 DoWork事宜处置惩罚函数中增加耗时的运算,然后挪用它的RunWorkerAsync要领就能够了。
private BackgroundWorker _demoBGWorker = new BackgroundWorker(); _demoBGWorker.DoWork += BGWorker_DoWork; _demoBGWorker.RunWorkerAsync(); private void BGWorker_DoWork(object sender, DoWorkEventArgs e) { //在这里实行耗时的运算。 int sum = 0; for (int i = 0; i <= 100; i++) { sum += i; } }
是不是是有点太简朴了?那末让我们斟酌下面的题目:
假如我们想要把参数通报给运算历程该怎样做?
在运算历程当中我们愿望把及时的信息显现在UI上该怎样办?
假如我们想要作废正在举行的运算该怎样办?
假如运算历程涌现非常我们又该怎样处置惩罚?
接下来我们就一个一个的处置惩罚这些题目。
把参数通报给运算历程
直接把100写死到运算历程当中可不好,我们还盘算许可用户指定乞降的局限呢!所以须要把100作为参数通报给盘算历程。在概述中我们经由历程挪用RunWorkerAsync要领启动盘算历程,实在这个要领能够接收一个 object 范例的参数。经由历程它我们就能够把任何数据通报给盘算历程:
//别忘了设置滚动条。 this.progressBarSum.Maximum = 100; _demoBGWorker.RunWorkerAsync(100); //下面是更新后的 BGWorker_DoWork 要领: private void BGWorker_DoWork(object sender, DoWorkEventArgs e) { //在这里实行耗时的运算。 int endNumber = 0; if(e.Argument != null) { endNumber = (int)e.Argument; } int sum = 0; for (int i = 0; i <= endNumber; i++) { sum += i; } }
BGWorker_DoWork事宜处置惩罚函数经由历程参数 e 的Argument属性传来了我们希冀的运算信息。
把音讯通报给UI
因为盘算历程比较长,我们在经由历程进度条来显现当前进度的同时,还愿望能及时的把盘算的中心效果显现在UI上。固然,BackgroundWorker对这个用例也供应了很好的支撑。它许可我们在实行盘算的历程当中给UI线程发送音讯,下面看看细致的做法:
_demoBGWorker.WorkerReportsProgress = true; _demoBGWorker.ProgressChanged += BGWorker_ProgressChanged;
起首要把WorkerReportsProgress 属性设置为 true,然后为ProgressChanged 事宜增加处置惩罚要领:
private void BGWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) { //修正进度条的显现。 this.progressBarSum.Value = e.ProgressPercentage; //假如有更多的信息须要通报,能够运用 e.UserState 通报一个自定义的范例。 //这是一个 object 范例的对象,您能够经由历程它通报任何范例。 //我们仅把当前 sum 的值经由历程 e.UserState 传回,并经由历程显现在窗口上。 string message = e.UserState.ToString(); this.labelSum.Text = message; }
继承更新 BGWorker_DoWork要领:
private void BGWorker_DoWork(object sender, DoWorkEventArgs e) { BackgroundWorker bgWorker = sender as BackgroundWorker; int endNumber = 0; if(e.Argument != null) { endNumber = (int)e.Argument; } int sum = 0; for (int i = 0; i <= endNumber; i++) { sum += i; string message = "Current sum is: " + sum.ToString(); //ReportProgress 要领把信息通报给 ProcessChanged 事宜处置惩罚函数。 //第一个参数范例为 int,示意实行进度。 //假如有更多的信息须要通报,能够运用 ReportProgress 的第二个参数。 //这里我们给第二个参数传进去一条音讯。 bgWorker.ReportProgress(i, message); Thread.Sleep(600); } }
OK,如今已能够看到进度条和实行信息的更新了。
作废操纵
在实行历程当中许可用户作废当前的操纵是一个基础的设想,BackgroundWorker天然有很好的支撑:
_demoBGWorker.WorkerSupportsCancellation = true;
和WorkerReportsProgress属性一样,假如要支撑作废操纵我们须要设置 WorkerSupportsCancellation属性为 true。而且还要在BGWorker_DoWork要领中举行支撑,在 for 循环中 Thread.Sleep(600)背面增加代码:
bgWorker.ReportProgress(i, message); Thread.Sleep(600); //在操纵的历程当中须要搜检用户是不是作废了当前的操纵。 if (bgWorker.CancellationPending == true) { e.Cancel = true; break; }
假如检测到用户点击的作废按钮,就退出当前的盘算历程。下面是点击作废按钮时要挪用的代码:
_demoBGWorker.CancelAsync();
如今已能够支撑作废操纵了,连忙尝尝吧!
非常处置惩罚
假如在盘算历程当中发生了非常该怎样处置惩罚?有无方法晓得盘算历程已完毕?固然要有,即便是一般的完毕也须要拿到盘算的效果。
_demoBGWorker.RunWorkerCompleted += BGWorker_RunWorkerCompleted; private void BGWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { //假如用户作废了当前操纵就封闭窗口。 if (e.Cancelled) { this.Close(); } //盘算已完毕,须要禁用作废按钮。 this.btnCancel.Enabled = false; //盘算历程当中的非常会被捉住,在这里能够举行处置惩罚。 if (e.Error != null) { Type errorType = e.Error.GetType(); switch (errorType.Name) { case "ArgumentNullException": case "MyException": //do something. break; default: //do something. break; } } //盘算效果信息:e.Result //use it do something. }
RunWorkerCompleted 事宜处置惩罚函数会在DoWork 事宜处置惩罚函数返回后被挪用。经由历程它我们能够举行一些运算完毕后的操纵,比方禁用作废按钮,非常处置惩罚,效果显现等。
注重,假如想要拿到 e.Result,您须要在BGWorker_DoWork要领中设置 e.Result属性,如:
e.Result = sum;
总结,BackgroundWorker 类功用完美且运用轻便,实在是处置惩罚异步耗时操纵的利器!
以上就是C#中BackgroundWorker用法的详解(图)的细致内容,更多请关注ki4网别的相干文章!