C# BackgroundWorker实现WinForm异步操作的例子

2024-04-07 07:58

本文主要是介绍C# BackgroundWorker实现WinForm异步操作的例子,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

1、场景描述

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

background._01_01

2、代码实现

由于界面上左右两边是两个互不干扰、相互独立的操作,所以分别创建了两个BackgroundWorker组件来负责(如下图:backgroundWorkerLeft和backgroundWorkerRight)。

background._01_2

将两个BackgroundWorker的WorkerReportsProgress和WorkerSupportsCancellation设为true。

background._01_03

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

private static int MaxRecords = 100;

下面是左边Start按钮的Click event handler:

private void buttonStartLeft_Click(object sender, EventArgs e)
{
    if (this.backgroundWorkerLeft.IsBusy)
    {
return;
    }
    this.listBoxLeft.Items.Clear();
    this.backgroundWorkerLeft.RunWorkerAsync(MaxRecords);
    this.buttonStartLeft.Enabled = false;
    this.buttonCacnelLeft.Enabled = true;
}

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

private void backgroundWorkerLeft_DoWork(object sender, DoWorkEventArgs e)
{
    try
    {
e.Result = this.RetrieveData(this.backgroundWorkerLeft, e);
    }
    catch (Exception ex)
    {
       MessageBox.Show(ex.Message);
       throw;
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

private int RetrieveData(BackgroundWorker worker, DoWorkEventArgs e)
{
    int maxRecords = (int)e.Argument;
    int percent = 0;
    for (int i = 1; i <= maxRecords; i++)
    {
        if (worker.CancellationPending)
        {
            return i;
        }

        percent = (int)(((double)i / (double)maxRecords) * 100);
        worker.ReportProgress(percent, new KeyValuePair<int,string>(i,Guid.NewGuid().ToString()));
        Thread.Sleep(100);
    }

    return maxRecords;
}

通过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 backgroundWorkerLeft_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    KeyValuePair<int,string> record = (KeyValuePair<int,string>) e.UserState ;
    this.labelResultLeft.Text = string.Format("There are {0} records retrieved!", record.Key);
    this.progressBarLeft.Value = e.ProgressPercentage;
    this.listBoxLeft.Items.Add(record.Value);
}

注:这些操作需要操作UI上的控件,只能在Main Thread中进行。如何在RetrieveData方法进行的话,由于该方式是一个异步方法,是会抛出异常的。

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

private void buttonCacnelLeft_Click(object sender, EventArgs e)
{
    this.backgroundWorkerLeft.CancelAsync();
}

 

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

event handler的定义:

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

上面介绍的是界面左边功能的实现,右边部分的实现完全一致。干兴趣的朋友可以参考Source Code.

这篇关于C# BackgroundWorker实现WinForm异步操作的例子的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/882043

相关文章

C#实现将XML数据自动化地写入Excel文件

《C#实现将XML数据自动化地写入Excel文件》在现代企业级应用中,数据处理与报表生成是核心环节,本文将深入探讨如何利用C#和一款优秀的库,将XML数据自动化地写入Excel文件,有需要的小伙伴可以... 目录理解XML数据结构与Excel的对应关系引入高效工具:使用Spire.XLS for .NETC

Nginx更新SSL证书的实现步骤

《Nginx更新SSL证书的实现步骤》本文主要介绍了Nginx更新SSL证书的实现步骤,包括下载新证书、备份旧证书、配置新证书、验证配置及遇到问题时的解决方法,感兴趣的了解一下... 目录1 下载最新的SSL证书文件2 备份旧的SSL证书文件3 配置新证书4 验证配置5 遇到的http://www.cppc

Nginx之https证书配置实现

《Nginx之https证书配置实现》本文主要介绍了Nginx之https证书配置的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起... 目录背景介绍为什么不能部署在 IIS 或 NAT 设备上?具体实现证书获取nginx配置扩展结果验证

C#如何在Excel文档中获取分页信息

《C#如何在Excel文档中获取分页信息》在日常工作中,我们经常需要处理大量的Excel数据,本文将深入探讨如何利用Spire.XLSfor.NET,高效准确地获取Excel文档中的分页信息,包括水平... 目录理解Excel中的分页机制借助 Spire.XLS for .NET 获取分页信息为什么选择 S

SpringBoot整合 Quartz实现定时推送实战指南

《SpringBoot整合Quartz实现定时推送实战指南》文章介绍了SpringBoot中使用Quartz动态定时任务和任务持久化实现多条不确定结束时间并提前N分钟推送的方案,本文结合实例代码给大... 目录前言一、Quartz 是什么?1、核心定位:解决什么问题?2、Quartz 核心组件二、使用步骤1

使用Redis实现会话管理的示例代码

《使用Redis实现会话管理的示例代码》文章介绍了如何使用Redis实现会话管理,包括会话的创建、读取、更新和删除操作,通过设置会话超时时间并重置,可以确保会话在用户持续活动期间不会过期,此外,展示了... 目录1. 会话管理的基本概念2. 使用Redis实现会话管理2.1 引入依赖2.2 会话管理基本操作

mybatis-plus分表实现案例(附示例代码)

《mybatis-plus分表实现案例(附示例代码)》MyBatis-Plus是一个MyBatis的增强工具,在MyBatis的基础上只做增强不做改变,为简化开发、提高效率而生,:本文主要介绍my... 目录文档说明数据库水平分表思路1. 为什么要水平分表2. 核心设计要点3.基于数据库水平分表注意事项示例

MySQL游标和触发器的操作流程

《MySQL游标和触发器的操作流程》本文介绍了MySQL中的游标和触发器的使用方法,游标可以对查询结果集进行逐行处理,而触发器则可以在数据表发生更改时自动执行预定义的操作,感兴趣的朋友跟随小编一起看看... 目录游标游标的操作流程1. 定义游标2.打开游标3.利用游标检索数据4.关闭游标例题触发器触发器的基

C#高效实现在Word文档中自动化创建图表的可视化方案

《C#高效实现在Word文档中自动化创建图表的可视化方案》本文将深入探讨如何利用C#,结合一款功能强大的第三方库,实现在Word文档中自动化创建图表,为你的数据呈现和报告生成提供一套实用且高效的解决方... 目录Word文档图表自动化:为什么选择C#?从零开始:C#实现Word文档图表的基本步骤深度优化:C

nginx跨域访问配置的几种方法实现

《nginx跨域访问配置的几种方法实现》本文详细介绍了Nginx跨域配置方法,包括基本配置、只允许指定域名、携带Cookie的跨域、动态设置允许的Origin、支持不同路径的跨域控制、静态资源跨域以及... 目录一、基本跨域配置二、只允许指定域名跨域三、完整示例四、配置后重载 nginx五、注意事项六、支持