C#异步编程方法

本文介绍了C#中实现异步编程的两种方法:使用委托的BeginInvoke和EndInvoke方法操作线程,以及使用BackgroundWorker组件。在WPF中,BeginInvoke用于异步调用UI线程,而BackgroundWorker组件方便执行耗时操作并支持进度报告和取消操作。
摘要由CSDN通过智能技术生成

C# 异步编程方法

  在WPF中等待UI响应时通常使用异步编程,主要使用的方法有:

一、用委托(Delegate)的BeginInvoke和EndInvoke方法操作线程

  通常,WPF 应用程序从两个线程开始:一个用于处理呈现,一个用于管理 UI。呈现线程有效地隐藏在后台运行,而 UI 线程则接收输入、处理事件、绘制屏幕以及运行应用程序代码。大多数应用程序都使用一个 UI 线程,但在某些情况下,最好使用多个线程。我们将在后面举例说明这一点。

  UI 线程对一个名为 Dispatcher 的对象内的工作项进行排队。Dispatcher 基于优先级选择工作项,并运行每一个工作项,直到完成。每个 UI 线程都必须至少有一个 Dispatcher,并且每个 Dispatcher 都只能在一个线程中执行工作项。

  要构建响应速度快、且用户友好的应用程序,诀窍是减小工作项,以最大限度地提高 Dispatcher 吞吐量。 这样,工作项将永远不会因为在 Dispatcher 队列中等待处理而失效。 输入与响应之间的任何可察觉的延迟都会使用户不快。

  那么,WPF 应用程序应如何处理大型操作呢?如果您的代码涉及大型计算,或者需要查询某台远程服务器上的数据库,应怎么办呢?通常的办法是在单独的线程中处理大型操作,而专门让 UI 线程来负责处理 Dispatcher 队列中的工作项。当大型操作完成时,可以将结果报告给 UI 线程来显示。

  一直以来,Windows 只允许创建 UI 元素的线程访问这些元素。这意味着负责某项长时间运行任务的后台线程无法更新已完成的文本框。Windows 这样做是为了确保 UI 组件的完整性。如果列表框的内容在绘制过程中被后台线程更新,那么该列表框看上去将会很奇怪。

  WPF 使用一种内置互斥机制来强制执行这种协调。WPF 中的大多数类都派生自 DispatcherObject。DispatcherObject 在构造时存储对链接到当前所运行线程的 Dispatcher 的引用。实际上,DispatcherObject 与创建它的线程关联。在程序执行过程中,DispatcherObject 可以调用它的公共 VerifyAccess 方法。VerifyAccess 检查与当前线程关联的Dispatcher,并将它与构造过程中存储的 Dispatcher 引用进行比较。如果两者不匹配,VerifyAccess 将引发异常。VerifyAccess 用于在每个属于 DispatcherObject 的方法的开头调用。

  如果只有一个线程可以修改 UI,那么后台线程如何与用户交互呢?后台线程可以请求 UI 线程代表它执行操作。这是通过向 UI 线程的 Dispatcher 注册工作项来完成的。Dispatcher 类提供两个注册工作项的方法:Invoke 和 BeginInvoke。这两个方法均调度一个委托来执行。Invoke 是同步调用,也就是说,直到 UI 线程实际执行完该委托它才返回。BeginInvoke 是异步的,将立即返回。

  Dispatcher 按优先级对其队列中的元素进行排序。 向 Dispatcher 队列中添加元素时可指定 10 个级别。 这些优先级在 DispatcherPriority 枚举中维护。 有关 DispatcherPriority 级别的详细信息可以在 Windows SDK 文档中找到。
  BeginInvoke方法可以使用线程异步地执行委托所指向的方法。然后通过EndInvoke方法获得方法的返回值(EndInvoke方法的返回值就是被调用方法的返回值),或是确定方法已经被成功调用。我们可以通过四种方法从EndInvoke方法来获得返回值。
例如:

this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal,
                    (ThreadStart)delegate()
        {
            //TODO
        });

参考链接:https://msdn.microsoft.com/zh-cn/library/ms741870.aspx#threading_overview

二、使用BackgroundWorker组件

  BackgroundWorker 组件用来执行诸如数据库事务、文件下载等耗时的异步操作。
  为了开始在后台操作,必须调用BackgroundWorker的RunWorkerAsync()方法,当调用此方时,BackgroundWorker 通过触发DoWork 事件,开始执行后台操作,DoWork 事件的代码是在另一个线程里执行的。

常用方法

  1.RunWorkerAsync
  开始执行后台操作。引发 DoWork 事件

  2.CancelAsync
  请求取消挂起的后台操作。
  注意:这个方法是将 CancellationPending 属性设置为 true,并不会终止后台操作。在后台操作中要检查 CancellationPending 属性,来决定是否要继续执行耗时的操作。

  3.ReportProgress
  引发 ProgressChanged 事件。

常用属性

  1.CancellationPending
  指示应用程序是否已请求取消后台操作。
  只读属性,默认为 false,当执行了 CancelAsync 方法后,值为 true。

  2.WorkerSupportsCancellation
  指示是否支持异步取消。
  要执行 CancelAsync 方法,需要先设置该属性为 true。

  3.WorkerReportsProgress
  指示是否能报告进度。要执行 ReportProgress 方法,需要先设置该属性为 true。

常用事件

  1.DoWork
  调用 RunWorkerAsync 方法时发生。

  2.RunWorkerCompleted
  后台操作已完成、被取消或引发异常时发生。

  3.ProgressChanged
  调用 ReportProgress 方法时发生。

  在 DoWork 事件处理程序中不操作任何用户界面对象。而应该通过 ProgressChanged 和 RunWorkerCompleted 事件与用户界面进行通信。

  如果想在 DoWork 事件处理程序中和用户界面的控件通信,可在用 ReportProgress 方法。
ReportProgress(int percentProgress, object userState),可以传递一个对象。

  ProgressChanged 事件可以从参数 ProgressChangedEventArgs 类的 UserState 属性得到这个信息对象。

  简单的程序用 BackgroundWorker 比 Thread 方便,Thread 中和用户界面上的控件通信比较麻烦,需要用委托来调用控件的 Invoke 或 BeginInvoke 方法,没有 BackgroundWorker 方便。
  参考链接:http://blog.itpub.net/23109131/viewspace-670314/

System.ComponentModel.BackgroundWorker backGroudWork = null;
//初始化
backGroudWork = new System.ComponentModel.BackgroundWorker();
//可取消
backGroudWork.WorkerSupportsCancellation = true;
backGroudWork.DoWork += new System.ComponentModel.DoWorkEventHandler(backGroudWork_DoWork);
backGroudWork.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(backGroudWork_RunWorkerCompleted);

void backGroudWork_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
    {
        //异步加载数据
    }


void backGroudWork_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
    {
        //异步加载完成
    }
pubulic void 启动后台线程(){
    this.backGroudWork.RunWorkerAsync();
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值