写了一个基于BackgorundWorker演示异步操作的例子。由于这个理基本上实现了BackgorundWorker的大部分功能:异步操作的启动、操作结束后的回调、异步操作的撤销和进度报告等等。尽管没有太多的技术含量,姑且放上来与大家分享。

1、场景描述

下面是程序运行时的截图。本程序模拟这样的一个场景:有两组相互独立的数据需要逐条获取和显示,当点击Start按钮,以异步的方式从存储介质中逐条获取数据,并将获取的数据追加到对应的ListBox中,ProgressBar真实反映以获取的数据条数和总记录条数的百分比,同时,当前获取的条数也会在下方的Label上随着操作的继续而动态变化。此外通过点击Stop按钮,可以中止掉当前的操作。当操作被中止后,ProgressBar和Label反映中止的那一刻的状态。

2、代码实现

由于界面上两个互不干扰、相互独立的操作,所以分别创建了BackgroundWorker组件来负责。

将BackgroundWorker的WorkerReportsProgress和WorkerSupportsCancellation设为true。

我们假设获取的记录数固定,我们为此定义一个常量:

private static int MaxRecords = 100;

下面是Start按钮的Click event handler:

当Start按钮被点击后,RunWorkerAsync方法被掉调用,我们定义的常量
(MaxRecords )当作参数被掺入。随后,将会触发其DoWork事件,Dowork event handler处理代码如下:

 private void btnStart_Click(object sender, EventArgs e)
{
if (this.backgroundWorker1.IsBusy)
{
return;
} this.listBox1.Items.Clear();
this.backgroundWorker1.RunWorkerAsync(maxRecords);
this.btnStart.Enabled = false;
this.btnCancle.Enabled = true;
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
try
{
e.Result=this.RetrieveData(this.backgroundWorker1,e);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
throw;
}
}

调用RetrieveData方法逐条获取数据。注意该方法的两个参数:

BackgroundWorker和DoWorkEventArgs 对象,返回值是返回数据的数量。由于在Start_Click中,我们将常量MaxRecords 作为参数传入了BackgroundWorker的RunWorkerAsync方法, 此时的e.Argument = MaxRecords。之所以要将这两个参数传入RetrieveData()方法,是因为该方法是为两个BackgroundWorker服务的,需要通过参数来区别当前是哪个BackgroundWorker。我们再来看看RetrieveData方法的定义:

  private int RetrieveData(BackgroundWorker backgroundWorker, DoWorkEventArgs e)
{
int SumRecords = (int)e.Argument;
int pecent = ;
for (int i = ; i < SumRecords; i++)
{
if (backgroundWorker.CancellationPending)
return i;
pecent = (int)((double)i / (double)SumRecords * );
backgroundWorker.ReportProgress(pecent, new KeyValuePair<int, string>(i, Guid.NewGuid().ToString()));
Thread.Sleep(); }
return SumRecords;
}

通过e.Argument,获得最大数据获取量之后,进行一个for循环,在每次迭代中,如何worker.CancellationPending==true,代表异步操作被显示取消,则直接返回;否则,调用BackgroundWorker的ReportProgress方法。ReportProgress具有两个重载:

  • public void ReportProgress(int percentProgress);
  • public void ReportProgress(int percentProgress, object userState);

percentProgress代表当前进度,从0-100。userState便于传入一些额外的参数。在界面上,由于数据的当前数量需要实时地显示,而记录也是现取现加(取出一条就在ListBox上追加)。所以制定一个KeyValuePair<int,string>对象作为第二个参数。其中Key为当前记录数,Value是一个Guid,代表取出的数据。

ReportProgress的调用将会导致ProgressChanged事件被触发。ProgressChanged event handler用于显示当前进度、当前记录数量和显示获取的纪录:

 private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
KeyValuePair<int, string> record = (KeyValuePair<int, string>)e.UserState; this.lblProcess.Text = string.Format("There are {0} records retrieved!", record.Key); this.progressBar1.Value = e.ProgressPercentage; this.listBox1.Items.Add(record.Value);
}

注:这些操作需要操作UI上的控件,只能在Main Thread中进行。如何在

RetrieveData方法进行的话,由于该方式是一个异步方法,是会抛出异常的。

由于操作的时间可能无法预知,在长时间不能完全获取数据的情况下,用户可以需要手工结束掉当前的操作。这个操作实现在Stop按钮的Click事件中:

如何操作正常地结束,BackgroundWorker的RunWorkerCompleted会被触发,

下面是RunWorkerCompleted

 private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
try
{ this.lblProcess.Text = string.Format("Total records: {0}", e.Result); this.btnStart.Enabled = true;
this.btnCancle.Enabled = false; } catch (TargetInvocationException ex)
{ MessageBox.Show(ex.InnerException.GetType().ToString()); }
}

event handler的定义:

上面介绍的是功能的实现.

C# 使用BackgroundWorker实现WinForm异步的更多相关文章

  1. 在UI程序设计中使用BackgroundWorker进行多线程异步处

    WinForm的应用程序中如果执行了一个的非常冗长的处理操作,(比如文件检索,大运算量计算),在执行时就会锁定用户界面,虽然主活动窗口还在运行,但用户无法与程序交互,无法移动窗体或改变窗体大小,导致程 ...

  2. winform异步进度条LongTime

    winform异步进度条LongTime,运用到回调函数 定义事件的参数类: namespace LongTime.Business { // 定义事件的参数类 public class ValueE ...

  3. System.ComponentModel.BackgroundWorker在WinForm中的异步使用

    为了防止操作过程中界面卡死,和WinForm搭配最适合的就是BackgroundWorker了.BackgroundWorker 类 using System; using System.Compon ...

  4. winform异步系统升级—BackgroundWorker

    BackgroundWorker用法实例 自己的代码,就是要执行的代码写到dowork里,ProgressChanged事件是控制进度时用的,最后的Completed事件进度完成,也就是dowork里 ...

  5. winform BackgroundWorker 的用法 - 异步执行

    1.设置 backgroundWorker1.WorkerReportsProgress = true; backgroundWorker1.WorkerSupportsCancellation = ...

  6. 实现 winform 异步跨线程访问UI控件

    在开发winform时经常会用到多线程防止界面出现假死现象,比如当你单击某个按钮时,需要执行很多代码,但是在执行过程中想实时的将当前执行的情况报告给用户,类型进度条或文本什么的. 这个时候很显然,如果 ...

  7. 一个简单的webservice的demo(下)winform异步调用webservice

    绕了一大圈,又开始接触winform的项目来了,虽然很小吧.写一个winform的异步调用webservice的demo,还是简单的. 一个简单的Webservice的demo,简单模拟服务 一个简单 ...

  8. 1 Winform 异步更新控件

    刚才看到有人问为了winfrom中,在大数据绑定的时候出现画面假死的状态,为了解决这个问题希望通过再开一个线程来给控件绑定数据,可是画面还是会假死.现在看到的方法有1.掩耳盗铃法(Control.Ch ...

  9. winform异步加载数据到界面

    做一个学习记录. 有两个需求: 1.点击按钮,异步加载数据,不卡顿UI. 2.把获取的数据加载到gridview上面. 对于需求1,2,代码如下: public delegate void ShowD ...

随机推荐

  1. [深入理解Android卷一全文-第四章]深入理解zygote

    由于<深入理解Android 卷一>和<深入理解Android卷二>不再出版,而知识的传播不应该由于纸质媒介的问题而中断,所以我将在CSDN博客中全文转发这两本书的所有内容. ...

  2. mybatis由浅入深day01_5mybatis开发dao的方法(5.1SqlSession使用范围_5.2原始dao开发方法)

    5 mybatis开发dao的方法 5.1 SqlSession使用范围 5.1.1 SqlSessionFactoryBuilder 通过SqlSessionFactoryBuilder创建会话工厂 ...

  3. Java集合----Set集合

    Set集合 Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个 Set 集合中,则添加操作失败. Set 判断两个对象是否相同不是使用 == 运算符,而是根据 equals 方法 Ha ...

  4. Unity版本与虚拟现实头盔Deepoon大朋版本测试

    一.看这里 Unity官方与OC runtime版本兼容性说明: https://developer.oculus.com/documentation/game-engines/latest/conc ...

  5. React如何进行事件传参

    今天在学习React的es6语法的时候,发现了个有趣的现象,就是this的指向问题.es6的this不同于es5,它在创立函数伊始便已经存在了,而不是像es5一样,睡调用的函数,this指向谁.但是这 ...

  6. ReactiveCocoa - iOS开发的新框架

    本文转载至 http://www.infoq.com/cn/articles/reactivecocoa-ios-new-develop-framework ReactiveCocoa(其简称为RAC ...

  7. MUI 二维码扫描并跳转

    1 首页 index.html <li id="html/barcode.html" onclick="clicked(this.id)"> < ...

  8. 【BZOJ3003】LED BFS+状压DP

    [BZOJ3003]LED Description LED屏是由一个庞大的点阵小灯泡组成的,一开始每个小灯泡都不发光.每一行一共有N个小灯泡,依次标号为1~n.现在给定K个点,要求这K个点发光,其余点 ...

  9. 【算法】N Queens Problem

    /* ** 目前最快的N皇后递归解决方法 ** N Queens Problem ** 试探-回溯算法,递归实现 */ #include "stdafx.h" #include & ...

  10. maven学习(二)(转)

    一.maven父工程与子模块的拆分与聚合原理 问题描述:将ssh工程拆分为多个模块开发 1.1.拆分原理 创建一个maven project(pom),然后在创建三个子模块(maven moudule ...