基于事件的异步模式——BackgroundWorker

简介:

转自strangeman原文 基于事件的异步模式——BackgroundWorker

 

  实现异步处理的方法很多,经常用的有基于委托的方式,今天记录的是基于事件的异步模式。利用BackgroundWorker组件可以很轻松的实现异步处理,并且该组件还支持事件的取消、进度报告等功能。本文以计算两个数XY的和为例。

  通过反编译可以看到,这个组件内部也是通过异步委托实现的,报告进度、取消事件等运用了事件技术实现,而事件的本质其实就是委托。

程序界面如下图,其中三个文本框分别为两个加数和处理结果,两个按钮为计算和取消,按钮下方为进度条。

引入BackgroundWorker组件,为DoWorkProgressChangedRunWorkerCompleted三个事件指定方法。
WorkerReportsProgress属性设为true,以支持报告进度。
WorkerSupportsCancellation属性设置为true,以支持取消。

复制代码
public MainForm()
{

    InitializeComponent();
    this.backgroundWorker1.DoWork += this.BackgroundWorker1DoWork;
    this.backgroundWorker1.ProgressChanged += this.BackgroundWorker1ProgressChanged;
    this.backgroundWorker1.RunWorkerCompleted += this.BackgroundWorker1RunWorkerCompleted;
    this.backgroundWorker1.WorkerReportsProgress = true;
    this.backgroundWorker1.WorkerSupportsCancellation = true;
    this.buttonCancel.Enabled = false;
}
复制代码

 

 

 

3. 当点击计算按钮时,调用BackgroundWorkerRunWorkerAsync方法实现异步处理,该方法支持一个object类型的参数。这里用元组Tuple<int,int>传递XY的值。调用RunWorkerAsync方法,将触发DoWork事件。

this.backgroundWorker1.RunWorkerAsync(new Tuple<int,int>(Convert.ToInt32(this.textBoxX.Text), Convert.ToInt32(this.textBoxY.Text)));

 通过反编译看到以下实现代码:

 

复制代码
public void RunWorkerAsync(object argument)
{

    if (this.isRunning)
    {

        throw new InvalidOperationException(SR.GetString("BackgroundWorker_WorkerAlreadyRunning"));

    }

    this.isRunning = true;

    this.cancellationPending = false;

    this.asyncOperation = AsyncOperationManager.CreateOperation(null);

    this.threadStart.BeginInvoke(argument, null, null);

}
复制代码

 

可以看到其内部也是通过异步委托实现的,其中threadStart的定义:private delegate void WorkerThreadStartDelegate(object argument);就是一个委托类型。

 

4. 当点击取消按钮时,调用BackgroundWorkerCancelAsync方法,这将改变BackgroundWorkerCancellationPending属性的值为ture。当执行OnWork方法时可以根据CancellationPending属性,判断用户是否要取消事件。

this.backgroundWorker1.CancelAsync();  

 再看看其内部:

复制代码
public void CancelAsync()
{
    if (!this.WorkerSupportsCancellation)
    {
        throw new InvalidOperationException(SR.GetString("BackgroundWorker_WorkerDoesntSupportCancellation"));
    }

    this.cancellationPending = true;
}

 
复制代码

 

如上面所说,改变只读属性CancellationPending的值为ture

5. 这里在DoWork方法中
根据CancellationPending属性,判断是否取消。若取消,应在方法结束之前将DoWorkEventArgsCancel属性设置为ture。这将用于RunWorkerCompleted事件中判断事件取消还是正常完成。
通过ReportProgress方法报告进度, 调用该方法时传递了一个int类型的参数,该方法将触发ProgressChanged事件。

复制代码
void BackgroundWorker1DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
    for (int i = 0; i < 10; i++) {

System.Threading.Thread.Sleep(500);//模拟耗时操作

if (backgroundWorker1.CancellationPending) {
    e.Cancel = true
    return;
} else {
    backgroundWorker1.ReportProgress(i * 10);
}
    }
    var t = e.Argument as Tuple<int,int>;
    e.Result = t.Item1 + t.Item2;
}

 
复制代码

 

 

 再看报告进度是怎么基于事件实现的:

 

复制代码
1.我们调用的ReportProgress方法

public void ReportProgress(int percentProgress)
{
    this.ReportProgress(percentProgress, null);
}

2.ReportProgress另一个重载,可以带一个自定义参数,方便传递其他内容,例如一般安装程序中的“正在复制文件”,“正在注册相关组件”提示信息等。

public void ReportProgress(int percentProgress, object userState)
{
    if (!this.WorkerReportsProgress)
    {
     throw new InvalidOperationException(SR.GetString("BackgroundWorker_WorkerDoesntReportProgress"));
    }
    ProgressChangedEventArgs progressChangedEventArgs = new ProgressChangedEventArgs(percentProgress, userState);
    if (this.asyncOperation != null)
    {
    this.asyncOperation.Post(this.progressReporter, progressChangedEventArgs);

    return;
    }

    this.progressReporter(progressChangedEventArgs);

}
复制代码

 

3.触发事件

private void ProgressReporter(object arg)
{
    this.OnProgressChanged((ProgressChangedEventArgs)arg);
}

 

6. ProgressChanged事件,会将控制权交给UI线程。在其实现方法中根据ProgressChangedEventArgsProgressPercentage属性获取进度值。

void BackgroundWorker1ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
    this.progressBar1.Value = e.ProgressPercentage;
}

 

7. OnWork退出后,将调用RunWorkerCompleted事件。
根据RunWorkerCompletedEventArgsCancelled属性判断是否正常完成。
根据RunWorkerCompletedEventArgsResult属性获取处理结果。

复制代码
void BackgroundWorker1RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)

{

    this.textBoxResult.Text = e.Cancelled ? "Canceled" : e.Result.ToString();

    this.buttonCancel.Enabled = false;

    this.buttonCalculate.Enabled = true;

    this.progressBar1.Value = 100;

}
复制代码

 

 

 

8. 完整代码

  View Code

 


代码下载:点我

 

 

没有整理与归纳的知识,一文不值!高度概括与梳理的知识,才是自己真正的知识与技能。 永远不要让自己的自由、好奇、充满创造力的想法被现实的框架所束缚,让创造力自由成长吧! 多花时间,关心他(她)人,正如别人所关心你的。理想的腾飞与实现,没有别人的支持与帮助,是万万不能的。




    本文转自wenglabs博客园博客,原文链接:http://www.cnblogs.com/arxive/p/6697608.html ,如需转载请自行联系原作者





相关文章
|
数据采集 数据可视化 数据挖掘
Python爬虫实战:抓取网站数据并生成报表
本文将介绍如何使用Python编写简单而高效的网络爬虫,从指定的网站上抓取数据,并利用数据分析库生成可视化报表。通过学习本文内容,读者将能够掌握基本的爬虫技术和数据处理方法,为日后开发更复杂的数据采集与分析工具打下坚实基础。
|
Shell 网络安全 开发工具
Qt实用技巧:QtCreator使用git(gitHub)管理项目代码笔记
Qt实用技巧:QtCreator使用git(gitHub)管理项目代码笔记
Qt实用技巧:QtCreator使用git(gitHub)管理项目代码笔记
|
Java 关系型数据库 MySQL
SpringBoot 实现 MySQL 百万级数据量导出并避免 OOM 的解决方案!
SpringBoot 实现 MySQL 百万级数据量导出并避免 OOM 的解决方案!
1125 0
|
12月前
|
移动开发 前端开发 Java
Java最新图形化界面开发技术——JavaFx教程(含UI控件用法介绍、属性绑定、事件监听、FXML)
JavaFX是Java的下一代图形用户界面工具包。JavaFX是一组图形和媒体API,我们可以用它们来创建和部署富客户端应用程序。 JavaFX允许开发人员快速构建丰富的跨平台应用程序,允许开发人员在单个编程接口中组合图形,动画和UI控件。本文详细介绍了JavaFx的常见用法,相信读完本教程你一定有所收获!
10583 5
Java最新图形化界面开发技术——JavaFx教程(含UI控件用法介绍、属性绑定、事件监听、FXML)
|
机器学习/深度学习 人工智能 自然语言处理
【人工智能】TensorFlow简介,应用场景,使用方法以及项目实践及案例分析,附带源代码
TensorFlow是由Google Brain团队开发的开源机器学习库,广泛用于各种复杂的数学计算,特别是涉及深度学习的计算。它提供了丰富的工具和资源,用于构建和训练机器学习模型。TensorFlow的核心是计算图(Computation Graph),这是一种用于表示计算流程的图结构,由节点(代表操作)和边(代表数据流)组成。
647 0
|
C# UED 开发者
WPF动画大揭秘:掌握动画技巧,让你的界面动起来,告别枯燥与乏味!
【8月更文挑战第31天】在WPF应用开发中,动画能显著提升用户体验,使其更加生动有趣。本文将介绍WPF动画的基础知识和实现方法,包括平移、缩放、旋转等常见类型,并通过示例代码展示如何使用`DoubleAnimation`创建平移动画。此外,还将介绍动画触发器的使用,帮助开发者更好地控制动画效果,提升应用的吸引力。
706 0
|
设计模式 消息中间件 供应链
捕捉变化的风-用观察者模式提升用户体验
观察者模式是一种行为设计模式,允许对象之间定义一种订阅机制,以便在对象状态变化时通知多个观察者。它广泛应用于实现动态事件处理系统、用户界面元素的交互,或监测状态变化等场景。 文章中通过丰富的场景案例,展示了不使用观察者模式可能带来的问题,如紧耦合和难以维护;接着解释了如何应用观察者模式成功解决这些问题,通过主题和观察者的解耦,增强系统的灵活性和可扩展性。 进一步解释了观察者模式的工作原理,并介绍了其结构图和运行机制。该模式有助于在维护一致性和实时性方面提供优势,同时促使我们在高层次上分类对象间的交互。 最后
358 0
捕捉变化的风-用观察者模式提升用户体验
|
存储 网络协议 Linux
2023年IPoAC“鸟联网”仍然是最好的数据传输方式!
2023年IPoAC“鸟联网”仍然是最好的数据传输方式! 时过境迁,互联网发展不断,如今已是2023年。TCP/IP 网络模型已经能很好的保证网络信息的传输,但是他们相比于 IPoAC 还是“落后”。
1064 0
2023年IPoAC“鸟联网”仍然是最好的数据传输方式!
|
C#
WPF技术之IsHitTestVisible
在WPF中,IsHitTestVisible是一个控件上的依赖属性,用于指定该控件是否可以响应鼠标和触摸输入。IsHitTestVisible属性的类型为bool。
1117 1
|
算法 C++
解决方案-Visual Studio生成库(DLL&LIB)以及如何调用
解决方案-Visual Studio生成库(DLL&LIB)以及如何调用
2182 0