zoukankan      html  css  js  c++  java
  • 异步编程之EAP

    一、概述

    前面我们了解到了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}
     已经下载的字节数/总字节: {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

  • 相关阅读:
    自定义组件要加@click方法
    绑定样式
    647. Palindromic Substrings
    215. Kth Largest Element in an Array
    448. Find All Numbers Disappeared in an Array
    287. Find the Duplicate Number
    283. Move Zeroes
    234. Palindrome Linked List
    202. Happy Number
    217. Contains Duplicate
  • 原文地址:https://www.cnblogs.com/3xiaolonglong/p/10375259.html
Copyright © 2011-2022 走看看