異步編程之EAP

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.Media.SoundPlay

System.Net.WebClient

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 }
View Code

 

<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>
View Code


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

相關文章
相關標籤/搜索