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

.NET Framework 2.0中新增的BackgroundWorker 类为解决这个问题提供了方便、快捷的途径。BackgroundWorker 可以用于启动后台线程,并在后台计算结束后调用主线程的方法。

第一:主要的事件及参数。
          1.DoWork——当执行BackgroundWorker.RunWorkerAsync方法时会触发该事件,并且传递DoWorkEventArgs参;

2.RunWorkerCompleted——异步操作完成后会触发该事件,当然如果需要在操作过程中结束可以执行BackgroundWorker.CancelAsync方法要求异步调用中止,并且在异步委托操作中检测BackgroundWorker.CancellationPending属性如果为true的话,跳出异步调用,同时将DoWorkEventArgs.Cancel属性设为true,这样当退出异步调用的时候,可以让处理RunWorkerCompleted事件的函数知道是正常退出还是中途退出。
          3.ProgressChanged——操作处理中获得的处理状态变化,通过BackgroundWorker.ReportProgress(int)方法触发该事件,并且传递ProgressChangedEventArgs,其中包含了处理的百分比,这个参数在UI界面上设置progressbar控件。      
             第二:主要的方法。
         BackgroundWorker.RunWorkerAsync——“起动”异步调用的方法有两次重载RunWorkerAsync(),RunWorkerAsync(object argument),第二个重载提供了一个参数,可以供异步调用使用。(如果有多个参数要传递怎么办,使用一个类来传递他们吧)。调用该方法后会触发DoWork事件,并且为处理DoWork事件的函数DoWorkEventArg事件参数,其中包含了RunWorkerAsync传递的参数。在相应DoWork的处理函数中就可以做具体的复杂操作。
         BackgroundWorker.ReportProgress——需要在一个冗长的操作中向用户不断反馈进度,这样的话就可以调用的ReportProgress(int percent),在调用 ReportProgress 方法时,触发ProgressChanged事件。提供一个在 0 到 100 之间的整数,它表示后台活动已完成的百分比。你也可以提供任何对象作为第二个参数,允许你 给事件处理程序传递状态信息。作为传递到此过程的 ProgressChangedEventArgs 参数属性,百分比和你自己的对象(如果提供的话)均要被传递到 ProgressChanged 事件处理程序。这些属性被分别命名为 ProgressPercentage 和 UserState,并且你的事件处理程序可以以任何需要的方式使用它们。(注意:只有在BackgroundWorker.WorkerReportsProgress属性被设置为true该方法才可用)。
         BackgroundWorker.CancelAsync——但需要退出异步调用的时候,就调用的这个方法。但是样还不够,因为它仅仅是将BackgroudWorker.CancellationPending属性设置为true。你需要在具体的异步调用处理的时候,不断检查BackgroudWorker.CancellationPending是否为true,如果是真的话就退出。(注意:只有在BackgroundWorker.WorkerSupportsCancellation属性被设置为true该方法才可用)。

同样的功能使用委托的异步调用也可以实现,但使用BackgroundWorker的话会更加的简便快捷,可以节省开发时间。

在VS2005中添加了BackgroundWorker组件,该组件在多线程编程方面使用起来非常方便,然而在开始时由于没有搞清楚它的使用机制,走了不少的弯路,现在把我在使用它的过程中的经验与诸位分享一下。
    BackgroundWorker类中主要用到的有这列属性、方法和事件:
    重要属性:
    1、CancellationPending             获取一个值,指示应用程序是否已请求取消后台操作。通过在DoWork事件中判断CancellationPending属性可以认定是否需要取消后台操作(也就是结束线程);
    2、IsBusy                          获取一个值,指示 BackgroundWorker 是否正在运行异步操作。程序中使用IsBusy属性用来确定后台操作是否正在使用中;
    3、WorkerReportsProgress           获取或设置一个值,该值指示BackgroundWorker能否报告进度更新
    4、WorkerSupportsCancellation      获取或设置一个值,该值指示 BackgroundWorker 是否支持异步取消。设置WorkerSupportsCancellation为true使得程序可以调用CancelAsync方法提交终止挂起的后台操作的请求;
    重要方法:
    1、CancelAsync         请求取消挂起的后台操作
    2、RunWorkerAsync      开始执行后台操作
    3、ReportProgress      引发ProgressChanged事件  
    重要事件:
    1、DoWork              调用 RunWorkerAsync 时发生
    2、ProgressChanged     调用 ReportProgress 时发生
    3、RunWorkerCompleted  当后台操作已完成、被取消或引发异常时发生
    另外还有三个重要的参数是RunWorkerCompletedEventArgs以及DoWorkEventArgs、ProgressChangedEventArgs。
    BackgroundWorker的各属性、方法、事件的调用机制和顺序:

    从上图可见在整个生活周期内发生了3次重要的参数传递过程:
    参数传递1:此次的参数传递是将RunWorkerAsync(Object)中的Object传递到DoWork事件的DoWorkEventArgs.Argument,由于在这里只有一个参数可以传递,所以在实际应用往封装一个类,将整个实例化的类作为RunWorkerAsync的Object传递到DoWorkEventArgs.Argument;
    参数传递2:此次是将程序运行进度传递给ProgressChanged事件,实际使用中往往使用给方法和事件更新进度条或者日志信息;
    参数传递3:在DoWork事件结束之前,将后台线程产生的结果数据赋给DoWorkEventArgs.Result一边在RunWorkerCompleted事件中调用RunWorkerCompletedEventArgs.Result属性取得后台线程产生的结果。
    另外从上图可以看到DoWork事件是在后台线程中运行的,所以在该事件中不能够操作用户界面的内容,如果需要更新用户界面,可以使用ProgressChanged事件及RunWorkCompleted事件来实现。

明白了BagkgroundWorker的事件调用顺序和参数传递机制之后在使用该组件用于多线程编程的时候就可以轻松许多了。详细的实例可以在我写的天涯离线浏览器中看到。

在UI程序设计中使用BackgroundWorker进行多线程异步处的更多相关文章

  1. 【WPF/C#】使用BackgroundWorker实现多线程/异步操作

    做WPF时需要做一个异步加载时的Loading遮罩,搜Stackoverflow看到很多方法,看到了这个插件: BusyIndicator in the extended WPF Toolkit 同时 ...

  2. C#中的BackgroundWorker控件

    C#中的BackgroundWorker控件   Keywords: C# .NET BackgroundWorkerSource: http://txw1958.cnblogs.com/ Backg ...

  3. Android实战开发租赁管理软件(适配UI,数据的存储,多线程下载)课程分享

    亲爱的网友,我这里有套课程想和大家分享,假设对这个课程有兴趣的,能够加我的QQ2059055336和我联系. 课程内容简单介绍 我们软件是基于移动设备的.所以我们必定的选择了安卓作为我们的开发工具.课 ...

  4. Android中的几种多线程实现

    有以下几种方式: 1)Activity.runOnUiThread(Runnable) 2)View.post(Runnable) ;View.postDelay(Runnable , long) 3 ...

  5. 为何invalidate()不可以直接在UI线程中调用&invalidate与postInvalidate

    1.android ui操作为什么一定要在主线程中执行? 答:Android UI操作是单线程模型,关于UI更新的相关API(包括invalidate())都是按照单线程设计的,对于多线程运行时不安全 ...

  6. C# Winform 跨线程更新UI控件常用方法汇总(多线程访问UI控件)

    概述 C#Winform编程中,跨线程直接更新UI控件的做法是不正确的,会时常出现“线程间操作无效: 从不是创建控件的线程访问它”的异常.处理跨线程更新Winform UI控件常用的方法有4种:1. ...

  7. Android中的多进程、多线程

    前面几篇总结了进程.线程相关的知识.这里总结下关于Android中的多进程.多线程及其使用. 这里总结的Android中的多进程.多线程也是一个基础,可扩展的很多. Android中多进程 常见的几种 ...

  8. Python中的多进程、多线程和协程

    本文中的内容来自我的笔记.撰写过程中参考了胡俊峰老师<Python程序设计与数据科学导论>课程的内容. 并发处理:多进程和多线程 前置 概念: 并发:一段时间内同时推进多个任务,但不一定要 ...

  9. UI设计中的48dp定律【转】

    有朋友建议我偶尔写写技术类的文章,所以我打算开始穿插性的写一些偏技术方面的科普文章,尽量往小白能看懂的方向写,今天我来讲讲UI设计中的48dp定律. 那么先说说什么是dp ?其实对于一个非技术人员要把 ...

随机推荐

  1. python自动化运维六:paramiko

    paramiko是基于python实现的SSH2远程安全连接,支持认证以及密钥方式,可以实现远程命令执行,文件传输,中间SSH代理等功能.也就是采用SSH的方式进行远程访问.SSH登陆的方式可以参考之 ...

  2. 《转》使用nginx和php实时产生缩略图

    在做自动静态化的时候,突然想到下面这个场景,也给出了解决方法.亲,真的很实用,耐心看下去.     当我从后台上传一个截图之后,480*800的截图之后,当时就没有压缩出320*480的小缩略图.好吧 ...

  3. 查看物料凭证MB03 /MIGO A04-显示,R02-物料凭证

    当货物移动操作后,可以使用事物码MB03.MIGO查询最近一次生成的物料凭证, 如果未知凭证号,Table:MKPF / AUFM/EKBE MKPF 抬头:物料凭证 KEY: MBLNR 物料凭证编 ...

  4. Table control 相关

    转:晚上回去有时间看看 http://help.sap.com/saphelp_nw04/helpdata/en/9f/dbac1d35c111d1829f0000e829fbfe/frameset. ...

  5. Java for LeetCode 123 Best Time to Buy and Sell Stock III【HARD】

    Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...

  6. Java for LeetCode 108 Convert Sorted Array to Binary Search Tree

    Given an array where elements are sorted in ascending order, convert it to a height balanced BST. 解题 ...

  7. IOS UIlabel 、UIButton添加下划线

    1.给UILabel 添加下划线 UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(, , , )]; label.backgrou ...

  8. mini2440移植uboot 2011.03(下)

    参考博文: <u-boot-2011.03在mini2440/micro2440上的移植> 移植(五)添加nand支持: host@debian:~/soft/mini2440/u-boo ...

  9. 计算机中丢失OPENGL.dll

    开发OpenGL项目时,在VS开发环境下可能会出现如图所示的错误. 在c:\windows\system32和SysWow64文件夹下存在opengl32.dll,此时,所写程序能够正常编译,但是,程 ...

  10. zkeacms源码解读一

    1,app.UseZKEACMS 中注册可识别的路由 其中 CMS_Redirection 表中填写了跳转路由  对应的UrlRedirectService中将会读取所有的跳转规则. 有两个路由规则很 ...