一、概述

前面我们了解到了APM编程模式,但APM不支持对异步操作的取消和没有提供对进度报告的功能。

对于界面程序来说,进度报告和取消操作的支持也是必不可少的,为了支持这些功能,微软在.NET 2.0的时候提出了一个新的异步编程模型---基于事件的异步编程模型——EAP。

实现了基于事件的异步模式的类将具有一个或者多个以Async为后缀的方法和对应的Completed事件,并且这些类都支持异步方法的取消、进度报告。

然而在.NET类库中并不是所有的类都支持EAP的,可能有朋友会误认为是不是支持APM的类都支持EAP的呢?在.NET 类库中只有部分的类支持EAP的(并且也只有部分类支持APM),这些类有(共17个类):

System.Object的派生类型:

  System.Activies.WorkflowInvoke  

  System.Deployment.Application.ApplicationDeployment

  System.Deployment.Application.InPlaceHosingManager

  System.Net.Mail.SmtpClient

  System.Net.PeerToPeer.PeerNameResolver

  System.Net.PeerToPeer.Collaboration.ContactManager

  System.Net.PeerToPeer.Collaboration.Peer

  System.Net.PeerToPeer.Collaboration.PeerContact

  System.Net.PeerToPeer.Collaboration.PeerNearMe

  System.ServiceModel.Activities.WorkflowControlClient

  System.ServiceModel.Discovery.AnnoucementClient

  System.ServiceModel.Discovery.DiscoveryClient

System.ComponentModel.Component的派生类型:

System.ComponentModel.BackgroundWorker

System.Media.SoundPlay

System.Net.WebClient

System.Net.NetworkInformation.Ping

System.Windows.Forms.PictureBox(继承于Control类,Control类派生于Component类)

当我们调用实现基于事件的异步模式的类的 XxxAsync方法时,即代表开始了一个异步操作,该方法调用完之后会使一个线程池线程去执行耗时的操作。

二、Demo

下面以BackgroundWorker类制作一个下载文件的demo。

BackgroundWorker类关键点

调用函数RunWorkerAsync时,会触发DoWork事件;

调用函数ReportProgress时,会触发ProgressChanged事件;

当后台操作已完成、被取消或引发异常时发生时,会触发RunWorkerCompleted事件。

  1 using System;
2 using System.ComponentModel;
3 using System.IO;
4 using System.Net;
5 using System.Threading;
6 using System.Windows;
7
8 namespace Wpf_EAP
9 {
10 public class RequestState
11 {
12 private HttpWebRequest request;
13 public HttpWebRequest Request
14 {
15 get
16 {
17 return request;
18 }
19 set
20 {
21 request = value;
22 }
23 }
24 private HttpWebResponse response;
25 public HttpWebResponse Response
26 {
27 get
28 {
29 return response;
30 }
31 set
32 {
33 response = value;
34 }
35 }
36 public Stream ResponseStream;
37 public FileStream Filestream = null;
38
39 public byte[] BufferRead = new byte[1024];
40 public static int Index = 1;
41 public RequestState(string fileSavePath)
42 {
43 //string fileName = "Pic" + (Index++).ToString();
44 string fileName = "Pic";
45 string saveFilePath = fileSavePath + fileName + ".jpg";//以下载jpg图片为例
46 //if(File.Exists(saveFilePath))
47 //{
48 // File.Delete(saveFilePath);
49 //}
50 Filestream = new FileStream(saveFilePath, FileMode.OpenOrCreate);
51 }
52 }
53 /// <summary>
54 /// Interaction logic for MainWindow.xaml
55 /// </summary>
56 public partial class MainWindow : Window
57 {
58 private string downLoadUrl = @"https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=2298824648,1812234339&fm=200&gp=0.jpg";
59 public string DownLoadUrl
60 {
61 get { return downLoadUrl; }
62 set { downLoadUrl = value; }
63 }
64 private string fileSavePath = @"D:\360Downloads\";
65 public string FileSavePath
66 {
67 get { return fileSavePath; }
68 set { fileSavePath = value; }
69 }
70 private int downLoadSize = 0;
71 private BackgroundWorker bgWorker;
72 private RequestState requestState;
73 private long totalSize = 0;
74 public MainWindow()
75 {
76 InitializeComponent();
77 this.DataContext = this;
78 bgWorker = new BackgroundWorker();
79 bgWorker.WorkerSupportsCancellation = true;
80 bgWorker.WorkerReportsProgress = true;
81 bgWorker.DoWork += bgWorkerFileDownload_DoWork;
82 bgWorker.ProgressChanged += bgWorkerFileDownload_ProgressChanged;
83 bgWorker.RunWorkerCompleted += bgWorkerFileDownload_RunWorkerCompleted;
84
85 }
86 private void GetTotalSize()
87 {
88 HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(DownLoadUrl);
89 HttpWebResponse response = (HttpWebResponse)myHttpWebRequest.GetResponse();
90 totalSize = response.ContentLength;
91 response.Close();
92 }
93 private void bgWorkerFileDownload_DoWork(object sender, DoWorkEventArgs e)
94 {
95 BackgroundWorker bgworker = sender as BackgroundWorker;
96 try
97 {
98 GetTotalSize();
99 // Do the DownLoad operation
100 // Initialize an HttpWebRequest object
101 HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(DownLoadUrl);
102
103 // If the part of the file have been downloaded,
104 // The server should start sending data from the DownloadSize to the end of the data in the HTTP entity.
105 if (downLoadSize != 0)
106 {
107 myHttpWebRequest.AddRange(downLoadSize);
108 }
109
110 // assign HttpWebRequest instance to its request field.
111 requestState.Request = myHttpWebRequest;
112 requestState.Response = (HttpWebResponse)myHttpWebRequest.GetResponse();
113 requestState.ResponseStream = requestState.Response.GetResponseStream();
114 int readSize = 0;
115 while (true)
116 {
117 if (bgworker.CancellationPending == true)
118 {
119 e.Cancel = true;
120 break;
121 }
122
123 readSize = requestState.ResponseStream.Read(requestState.BufferRead, 0, requestState.BufferRead.Length);
124 if (readSize > 0)
125 {
126 downLoadSize += readSize;
127 int percentComplete = (int)((float)downLoadSize / (float)totalSize * 100);
128 requestState.Filestream.Write(requestState.BufferRead, 0, readSize);
129 Thread.Sleep(100);
130 // 报告进度,引发ProgressChanged事件的发生
131 bgworker.ReportProgress(percentComplete);
132 }
133 else
134 {
135 break;
136 }
137 }
138 }
139 catch(Exception err)
140 {
141 MessageBox.Show(err.Message);
142 }
143 }
144 private void bgWorkerFileDownload_ProgressChanged(object sender, ProgressChangedEventArgs e)
145 {
146 //progressBar.Value = e.ProgressPercentage;
147 Dispatcher.BeginInvoke(new Action( ()=> { progressBar.Value = e.ProgressPercentage; } ));
148 }
149 private void bgWorkerFileDownload_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
150 {
151 if (e.Error != null)
152 {
153 MessageBox.Show(e.Error.Message);
154 requestState.Response.Close();
155 }
156 else if (e.Cancelled)
157 {
158 int percentComplete = (int)((float)downLoadSize / (float)totalSize * 100);
159 MessageBox.Show(String.Format("下载暂停,下载的文件地址为:{0}\n 已经下载的字节数/总字节: {1}字节/{2} 百分比:{3} %", DownLoadUrl, downLoadSize, totalSize,percentComplete));
160 requestState.Response.Close();
161 requestState.Filestream.Close();
162
163 this.btnDownLoad.IsEnabled = true;
164 this.btnPause.IsEnabled = false;
165 }
166 else
167 {
168 MessageBox.Show(String.Format("下载已完成,下载的文件地址为:{0},文件的总字节数为: {1}字节", DownLoadUrl, totalSize));
169 downLoadSize = 0;
170 Dispatcher.BeginInvoke(new Action(() => { progressBar.Value = 0; }));
171 this.btnDownLoad.IsEnabled = true;
172 this.btnPause.IsEnabled = false;
173 requestState.Response.Close();
174 requestState.Filestream.Close();
175 }
176
177 }
178
179 private void btnPause_Click(object sender, RoutedEventArgs e)
180 {
181 if (bgWorker.IsBusy && bgWorker.WorkerSupportsCancellation == true)
182 {
183 // Pause the asynchronous operation
184 // Fire RunWorkerCompleted event
185 bgWorker.CancelAsync();
186 }
187 }
188
189 private void btnDownLoad_Click(object sender, RoutedEventArgs e)
190 {
191 if (bgWorker.IsBusy != true)
192 {
193 bgWorker.RunWorkerAsync();//触发DoWork事件
194 // Create an instance of the RequestState
195 requestState = new RequestState(FileSavePath);
196 requestState.Filestream.Seek(downLoadSize, SeekOrigin.Begin);
197 this.btnDownLoad.IsEnabled = false;
198 this.btnPause.IsEnabled = true;
199 }
200 else
201 {
202 MessageBox.Show("下载进行中,请稍后...");
203 }
204 }
205 }
206 }
<Window x:Class="Wpf_EAP.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Wpf_EAP"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<Label Content="DownLoadUrl:" FontSize="14" VerticalAlignment="Center" HorizontalAlignment="Right"></Label>
<Label Content="FileSavePath:" FontSize="14" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Right"></Label>
<TextBox FontSize="20" BorderBrush="Green" BorderThickness="1" Grid.Column="1" Margin="5" Grid.Row="1" Text="{Binding FileSavePath}" Name="tbSavePath"/>
<TextBox Text="{Binding DownLoadUrl}" FontSize="20" BorderBrush="Green" BorderThickness="1" Name="lbUrl" Grid.Column="1" Margin="5"/>
<Button Content="DownLoad" Grid.Column="2" Grid.Row="0" FontSize="20" Name="btnDownLoad" VerticalAlignment="Center" Click="btnDownLoad_Click"/>
<Button Content="Pause" Grid.Column="2" Grid.Row="1" FontSize="20" Name="btnPause" VerticalAlignment="Center" Click="btnPause_Click"/>
<ProgressBar Grid.Row="2" Grid.ColumnSpan="3" Height="30" Name="progressBar" Minimum="0" Maximum="100"></ProgressBar>
</Grid>
</Window>

注:本文参考https://www.cnblogs.com/zhili/archive/2013/05/11/EAP.html

异步编程之EAP的更多相关文章

  1. 异步编程之Generator(1)——领略魅力

    异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...

  2. 异步编程之Promise(3):拓展进阶

    异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...

  3. 异步编程之Promise(2):探究原理

    异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...

  4. (翻译)异步编程之Promise(1):初见魅力

    原文:https://www.promisejs.org/ by Forbes Lindesay 异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2) ...

  5. net异步编程之await

    net异步编程之await 初探asp.net异步编程之await   终于毕业了,也顺利进入一家期望的旅游互联网公司.27号入职.放肆了一个多月没写代码,好方啊. 另外一下观点均主要针对于await ...

  6. Javascript异步编程之setTimeout与setInterval详解分析(一)

    Javascript异步编程之setTimeout与setInterval 在谈到异步编程时,本人最主要会从以下三个方面来总结异步编程(注意:特别解释:是总结,本人也是菜鸟,所以总结不好的,请各位大牛 ...

  7. 异步编程之co——源码分析

    异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...

  8. 异步编程之Generator(2)——剖析特性

    异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...

  9. 【转】Javascript异步编程之setTimeout与setInterval

    Javascript异步编程之setTimeout与setInterval 转自:http://www.tuicool.com/articles/Ebueua 在谈到异步编程时,本人最主要会从以下三个 ...

随机推荐

  1. 从 Vue 中 parseHTML 方法来看前端 html 词法分析

    先前我们在 从 Vue parseHTML 所用正则来学习常用正则语法 这篇文章中分析了 parseHTML 方法用到的正则表达式,在这个基础上我们可以继续分析 parseHTML 方法. 先来看该方 ...

  2. [源码解析] 深度学习分布式训练框架 horovod (17) --- 弹性训练之容错

    [源码解析] 深度学习分布式训练框架 horovod (17) --- 弹性训练之容错 目录 [源码解析] 深度学习分布式训练框架 horovod (17) --- 弹性训练之容错 0x00 摘要 0 ...

  3. 【剑指offer】05. 替换空格

    剑指 Offer 05. 替换空格 知识点:: 题目描述 请实现一个函数,把字符串 s 中的每个空格替换成"%20". 示例 输入:s = "We are happy.& ...

  4. Leetcode13. 罗马数字转整数Leetcode14. 最长公共前缀Leetcode15. 三数之和Leetcode16. 最接近的三数之和Leetcode17. 电话号码的字母组合

    > 简洁易懂讲清原理,讲不清你来打我~ 输入字符串,输出对应整数 ![在这里插入图片描述](https://img-blog.csdnimg.cn/63802fda72be45eba98d9e4 ...

  5. 微信小程序云开发-云存储-上传文件(word/excel/ppt/pdf)到云存储

    说明 word/excel/ppt/pdf是从客户端会话选择文件.使用chooseMessageFile中选择文件. 一.wxml文件 上传按钮,绑定chooseFile <!--上传文件(wo ...

  6. PHP如何接收json数据

    以前一直在写一些网站,很少涉及到接口的东西.最近公司在做一个平台,需要往接口上发送json数据.闲话少叙,直接上干货. 在php中可以通过如下方式获取: file_get_contents(" ...

  7. POJ3662

    poj3662 大意:n个点p条边的无向图,求在删去k条边后使1和n号点联通路径上的最长边最小值. 一开始理解错题意以为是分层图求最短路径,结果写完发现k太大了发现事情没有那么简单(讨厌英语题面!) ...

  8. 数据库开发之ETL概念

    原文链接:https://blog.csdn.net/jianzhang11/article/details/104240047/ ETL基础概念 - 背景随着企业的发展,各业务线.产品线.部门都会承 ...

  9. odoo检查规则

    @api.multidef button_cancel(self): for move in self: if not move.journal_id.update_posted: raise Use ...

  10. Python - 基础数据类型 tuple 元组

    元组简单介绍 元组是一个和列表和相似的数据类型,也是一个有序序列 两者拥有着基本相同的特性,但是也有很多不同的地方 声明元组 var = (1, 2, 3) var = ("1", ...