1、概述html
前面咱們瞭解到了APM編程模式,但APM不支持對異步操做的取消和沒有提供對進度報告的功能。web
對於界面程序來講,進度報告和取消操做的支持也是必不可少的,爲了支持這些功能,微軟在.NET 2.0的時候提出了一個新的異步編程模型---基於事件的異步編程模型——EAP。express
實現了基於事件的異步模式的類將具備一個或者多個以Async爲後綴的方法和對應的Completed事件,而且這些類都支持異步方法的取消、進度報告。 編程
然而在.NET類庫中並非全部的類都支持EAP的,可能有朋友會誤認爲是否是支持APM的類都支持EAP的呢?在.NET 類庫中只有部分的類支持EAP的(而且也只有部分類支持APM),這些類有(共17個類): windows
System.Object的派生類型:異步
System.Activies.WorkflowInvoke async
System.Deployment.Application.ApplicationDeploymentide
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.Net.NetworkInformation.Ping
System.Windows.Forms.PictureBox(繼承於Control類,Control類派生於Component類)
當咱們調用實現基於事件的異步模式的類的 XxxAsync方法時,即表明開始了一個異步操做,該方法調用完以後會使一個線程池線程去執行耗時的操做。
2、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