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

1 篇文章 0 订阅

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 内容,如图:

    image

  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方法,报告进度

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

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

  • 13
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值