分享一个在 WinForm 桌面程序中使用进度条展示报表处理进度的例子,提升用户体验

news2024/11/15 8:17:23

image

前言

在有些比较消耗时间的业务场景中,比如生成报表等,如果没有在操作的过程中向用户反馈操作进度,会让用户以为程序 “死” 掉了,用户体验非常不好。

WinForm 桌面程序项目与 Console 项目不一样,如果 Console 项目,我们可以在处理业务的关键节点时,在控制台打印一些消息向用户报告进度,但是 WinForm 桌面程序项目出于线程安全的原因,是无法在处理业务的过程中同时显示 UI 控件的消息的,即你在处理业务的的关键节点时,向 UI 控件如 TextBox 写一些消息,但实际上 UI 是不会马上同时显示你写的消息的,只有在整个业务处理完后,UI 才会呈现你写的消息,但这时已经太迟了,没有太多意义。所以在 WinForm 桌面程序项目里,要在操作的过程中向用户反馈操作进度,只能通过多线程来处理,一个线程在后台处理业务,一个线程通过委托同步展示业务处理进度,不过手动写多线程代码比较麻烦,所以微软在 .NET 2.0 增加了 BackgroundWorker 类,专门用于处理这种情况。使用 BackgroundWorker 可以轻松地启动一个单独的线程上执行一些操作并进行管理,无需我们操心。

可以将它从 “工具箱” 的 “组件” 选项卡中拖到窗体上,也可以通过编程方式创建 BackgroundWorker 类,本文通过一个实际的详细例子演示如何通过编程方式使用 BackgroundWorker 类,大家可以照着做。

Step By Step 步骤

  1. 创建一个 WinForm 类型的项目

  2. 设计窗体 UI 内容,如图:

    [图片]

  3. 打开窗体如 FrmZqReportHandler 的代码

  4. 在顶部(构造方法之前)添加声明 BackgroundWorker 对象的代码

    // 声明 BackgroundWorker 对象
    private BackgroundWorker m_BackgroundWorker;
    
  5. 在构造方法中实例化及配置 BackgroundWorker 对象,(留意注释

    public FrmZqReportHandler()
    {
    	InitializeComponent();
    
    	m_BackgroundWorker = new BackgroundWorker();            // 实例化 BackgroundWorker 对象
    	m_BackgroundWorker.WorkerReportsProgress = true;        // 设置可以通告进度
    	m_BackgroundWorker.WorkerSupportsCancellation = false;  // 设置不可以取消
    
    	// 声明 DoWork 事件
    	m_BackgroundWorker.DoWork += new DoWorkEventHandler(DoWork);
    
    	// 声明 ProgressChanged 事件
    	m_BackgroundWorker.ProgressChanged += new ProgressChangedEventHandler(UpdateProgress);
    
    	// 声明 RunWorkerCompleted 事件
    	m_BackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(CompletedWork);
    }
    
  6. 在按钮的单击事件里启动 BackgroundWorker,(留意注释

    private void btnSelectFile_Click(object sender, EventArgs e)
    {
    	// 1. 选择文件
    	// 代码忽略 ......
    
    	// 2. 如果后台线程空闲,则启动后台操作
    	if (!m_BackgroundWorker.IsBusy) {
    		// 启动后台操作,触发 DoWork 事件
    		// 参数可传可不传,暂时没什么有什么作用
    		m_BackgroundWorker.RunWorkerAsync(this);
    	}
    }
    
  7. 编写 DoWork 事件,DoWork 事件中的代码就是后台线程要执行的业务处理方法,(留意注释

    void DoWork(object sender, DoWorkEventArgs e)
    {
    	BackgroundWorker bw = sender as BackgroundWorker;
    
    	// 1. 处理业务逻辑 01
    	// 处理业务逻辑代码 ......
    	// 传递进度,第一个参数是进度值,第二个参数是附加对象,此方法会触发 ProgressChanged 事件
    	bw.ReportProgress(10, obj);
    
    	// ...... 处理业务逻辑代码
    
    	// 7. 处理业务逻辑 07,业务处理完成
    	// 处理业务逻辑代码 ......
    	// 传递进度,将进度值设置为进度条控件的最大值
    	bw.ReportProgress(100, fileUrl);
    }
    
  8. 编写 ProgressChanged 事件,注意:在这个事件里跟 UI 控件交互,(留意注释

    void UpdateProgress(object sender, ProgressChangedEventArgs e)
    {
    	int progress = e.ProgressPercentage;
    	// 根据 `DoWork` 事件传递过来的进度值不断更新进度条的值
    	pgBar.Value = progress;
    
    	// 根据进度值向填写业务处理细节,提高用户体验
    	if (progress == 1)
    	{
    		txtPg.AppendText($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} ......\r\n");
    	}
    	else if (progress == 10)
    	{
    		txtPg.AppendText(......
    	}
    	// ......
    	else if (progress == 100)
    	{
    		txtPg.AppendText($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 数据处理后是 [{e.UserState}]\r\n");
    	}
    }
    
  9. 编写 RunWorkerCompleted 事件,此事件在后台操作已完成、被取消或引发异常时发生

    void CompletedWork(object sender, RunWorkerCompletedEventArgs e)
    {
    	if (e.Error != null)
    	{
    		txtPg.AppendText($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 处理过程中出现错误:[{e.Error}]\r\n");
    	}
    	else
    	{
    		txtPg.AppendText($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 处理完毕");
    	}
    }
    
  10. 至此,代码就完成了,运行效果如下:

    [图片]

总结

  1. BackgroundWorker 类虽然是旧技术,但它在处理 WinForm 业务处理进度,提高用户体验上却是非常好用的,比直接用多线程方便很多,这可见,技术不分新旧,用在恰当的地方最重要。
  2. BackgroundWorker 类几个常用属性
    1. WorkerReportsProgress: 设置能否报告进度,通常设置为 true
    2. WorkerSupportsCancellation: 设置能否中途取消,按需设置
    3. IsBusy: 判断后台线程是否正在工作中,只读属性
    4. CancellationPending: 指示应用程序是否已请求取消后台操作,只读属性
  3. BackgroundWorker 类几个常用方法
    1. RunWorkerAsync: 启动后台操作,此方法会触发 DoWork 事件
    2. CancelAsync: 请求取消挂起的后台操作,此方法只是将 CancellationPending 属性设置为 true,需要在 DoWork 事件中检查 CancellationPending 属性,来决定是否要继续取消后台操作
    3. ReportProgress: 报告进度,此方法会触发 ProgressChanged 事件
  4. BackgroundWorker 类几个常用事件
    1. DoWork: 后台线程,一般在这里处理业务逻辑,不能操作 UI 控件
    2. ProgressChanged: 报告业务处理进度,可以操作 UI 控件
    3. RunWorkerCompleted: 后台操作已完成、被取消或引发异常时触发,可以操作 UI 控件
  5. BackgroundWorker 类使用步骤:
    1. 新建 BackgroundWorder 对象
    2. 根据需求, 设置是否能取消、是否报告进度等
    3. 根据需求,设置好相关事件,DoWorker、ProgressChanged、RunWorkerCompleted
    4. 调用 RunWorkerAsyns() 方法,启动线程;
    5. DoWork 在需要取消的位置,判断 CancellationPending 的值,并做相关处理;
    6. DoWork 在适当的位置调用 ReportProgress方法,报告进度

我是老杨,一个奋斗在一线的资深研发老鸟,让我们一起聊聊技术,聊聊人生。

都看到这了,求个点赞、关注、在看三连呗,感谢支持。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1883409.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

农村程序员陈随易2024年中总结

今天是 2024年7月1日,时间如白驹过隙,今年已去其一半。 总结一下今年上半年的情况,给大家提供一些参考和建议。 希望大家关注一下公众号 陈随易,有些内容只在公众号发表。 先看看我的年初计划,这个在今年年初的时候&…

【解锁未来:深入了解机器学习的核心技术与实际应用】

解锁未来:深入了解机器学习的核心技术与实际应用 💎1.引言💎1.1 什么是机器学习? 💎2 机器学习的分类💎3 常用的机器学习算法💎3.1 线性回归(Linear Regression)&#x1…

141个图表,完美展示数据分类别关系!

本文介绍使用Python工具seaborn详细实现分类关系图表,包含8类图141个代码模版。 分类关系图表用于展示数字变量和一个或多个分类变量之间的关系,可以进一步分为:箱形图(box plot)、增强箱形图(enhanced bo…

C++进阶 | [4.3] 红黑树

摘要:什么是红黑树,模拟实现红黑树 红黑树 ,是一种 二叉搜索树 ,但 在每个结点上增加一个存储位表示结点的颜色,可以是 Red 或 Black 。 通过对 任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树…

创建XCOM窗体和跳转连接

Xcom 窗体&#xff1a; (groupBox组合框&#xff0c;comboBox下拉框) xcom代码&#xff1a; namespace _01_作业 {// 1kb 1024B 1200B// 1MB public partial class Form1 : Form{public List<string> botelv new List<string> { "600","1200&…

基于Tools体验NLP编程的魅力

大模型能理解自然语言&#xff0c;从而能解决问题&#xff0c;但是就像人类大脑一样&#xff0c;大脑只能发送指令&#xff0c;实际行动得靠四肢&#xff0c;所以LangChain4j提供的Tools机制就是大模型的四肢。 大模型的不足 大模型在解决问题时&#xff0c;是基于互联网上很…

图像大模型中的注意力和因果掩码

AIM — 图像领域中 LLM 的对应物。尽管 iGPT 已经存在 2 年多了&#xff0c;但自回归尚未得到充分探索。在本文中&#xff0c;作者表明&#xff0c;当使用 AIM 对网络进行预训练时&#xff0c;一组图像数据集上的下游任务的平均准确率会随着数据和参数的增加而线性增加。 要运…

Android 大话binder通信

戳蓝字“牛晓伟”关注我哦&#xff01; 用心坚持输出易读、有趣、有深度、高质量、体系化的技术文章 由于 Android 大话binder通信(上) 和 Android 大话binder通信(下) 分为两篇阅读体验不好&#xff0c;顾合并为一篇。 本文摘要 用故事的方式把binder通信的整个过程都描述…

机械原理介绍

机械原理介绍 1 介绍1.1 概述1.2 资料书籍在线资料 2 [机械原理知识整理](https://tomm.muzing.top/) 【muzing整理编写】1 绪论2 机构的结构分析2-2 机构的组成及分类2-3 机构运动简图2-4 机构具有确定运动的条件及最小阻力定律2-5 2-6 机构自由度的计算2-7 平面机构的组成原理…

【深度学习】图生图img3img论文原理,SD EDIT

https://arxiv.org/abs/2108.01073 摘要 引导图像合成技术使普通用户能够以最小的努力创建和编辑逼真的图像。关键挑战在于平衡对用户输入&#xff08;例如&#xff0c;手绘的彩色笔画&#xff09;的忠实度和合成图像的真实感。现有的基于GAN的方法试图通过使用条件GAN或GAN反…

64.WEB渗透测试-信息收集- WAF、框架组件识别(4)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;63.WEB渗透测试-信息收集- WAF、框架组件识别&#xff08;3&#xff09;-CSDN博客 我们在…

面经-计算机基础

1.计算机⽹络 1.1 OSI与TCP/IP各层的结构与功能,都有哪些协议? 计算机网络体系结构 应⽤层 应⽤层 (application-layer &#xff09;的任务是通过应⽤进程间的交互来完成特定⽹络应⽤。 应⽤层协议定 义的是应⽤进程&#xff08;进程&#xff1a;主机中正在运⾏的程序&…

便签 Pro(Mac 智能便签工具)专业版怎么样,值得购买吗?

使用 Mac 的小伙伴平时都是怎么记录工作生活中的碎片信息&#xff1f;用聊天软件&#xff0c;还是系统备忘录呢&#xff1f; 实际体验下来&#xff0c;其实都难以称得上好用。 赶紧来了解一下 Mac 多彩思维速记工具便签 Pro&#xff01;拥有智能边框大小、iCloud 同步、历史记…

昇思25天学习打卡营第1天|MindSpore 全流程操作指南

目录 MindSpore 库相关操作的导入指南 处理数据集 网络构建 模型训练 保存模型 加载模型 MindSpore 库相关操作的导入指南 首先&#xff0c;我们导入了 MindSpore 这个库的整个模块。然后&#xff0c;从 MindSpore 库中引入了 nn 模块&#xff0c;一般来说&#xff0c;它是…

JavaEE—什么是服务器?以及Tomcat安装到如何集成到IDEA中?

目录 ▐ 前言 ▐ JavaEE是指什么? ▐ 什么是服务器&#xff1f; ▐ Tomcat安装教程 * 修改服务端口号 ▐ 将Tomcat集成到IDEA中 ▐ 测试 ▐ 结语 ▐ 前言 至此&#xff0c;这半年来我已经完成了JavaSE&#xff0c;Mysql数据库&#xff0c;以及Web前端知识的学习了&am…

ROS2在rviz2中实时显示轨迹和点

本文是将《ROS在rviz中实时显示轨迹和点》博客中rviz轨迹显示转为ROS2环境中的rviz2显示。 ros2的工作空间创建这里就不展示了。 包的创建 ros2 pkg create --build-type ament_cmake showpath --dependencies rclcpp nav_msgs geometry_msgs tf2_geometry_msgsshowpath.cpp…

【微服务网关——Websocket代理】

1.Websocket协议与原理 1.1 连接建立协议 1.1.1 客户端发起连接请求 客户端通过 HTTP 请求发起 WebSocket 连接。以下是一个 WebSocket 握手请求的例子&#xff1a; GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key…

python 中的 下划线_ 是啥意思

在 Python 中&#xff0c;_&#xff08;下划线&#xff09;通常用作占位符&#xff0c;表示一个变量名&#xff0c;但程序中不会实际使用这个变量的值。 目录 忽略循环变量&#xff1a;忽略函数返回值&#xff1a;在解释器中使用&#xff1a;举例子1. 忽略循环变量2. 忽略不需…

APP逆向 day8 JAVA基础3

一.前言 昨天我们讲了点java基础2.0&#xff0c;发现是又臭又长&#xff0c;今天就是java基础的最后一章&#xff0c;也就是最难的&#xff0c;面向对象。上一末尾也是提到了面向对象&#xff0c;但是面向对象是最重要的&#xff0c;怎么可能只有这么短呢&#xff1f;所以今天…