2017-02-20 6 views
0

私はDownloadメソッドを持ち、ProgressChangedEventArgsProgressプロパティを持っています。 UIレスポンスを維持するには、Downloadメソッドを非同期にする必要があります。だから私は以下のコードを用意しましたが、にe.Progressを呼び出すと、クロススレッド操作の例外がスローされます。 asyncawaitの実装で間違っていますか? EventArgsを呼び出すことなくForm.csで非同期メソッド内で発生したEventArgsの使用方法

void Form1_Load(object sender, EventArgs e) 
    { 
     DownloadManager dm = new DownloadManager("http://download.thinkbroadband.com/20MB.zip", ""); 

     long size = 0; 
     bool res = false; 
     dm.checkUrl(ref size, ref res); 
     dm.ProgressChanged += dm_ProgressChanged; 
     dm.DownloadProcedure(size); 
    } 

    void dm_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     Text = e.Progress.ToString("0.00"); 
    } 

Form.cs

public async void DownloadProcedure(long contentLength) 
    { 
     await Task.Run(() => 
     { 
      long totalBytesReceived = 0; 
      int bytesRead = 0; 
      byte[] buffer = new byte[10 * 1024]; 
      HttpWebRequest req = url.CreateHttpWebRequest(); 
      HttpWebResponse resp = req.GetHttpWebResponse(); 
      Stream remoteStream = resp.GetResponseStream(); 

      while ((bytesRead = remoteStream.Read(buffer, 0, buffer.Length)) > 0) 
      { 
       totalBytesReceived += bytesRead; 
       double newProgress = (totalBytesReceived * 100d/contentLength); 
       if (progress != newProgress && ProgressChanged != null) 
       { 
        ProgressChanged(this, new ProgressChangedEventArgs(progress)); 
       } 
      } 
     }); 
    } 

DownloadManager.cs

はどうすればこの問題を解決することができますか?

+3

最善の解決策は、1にある) 'IProgress 'と '進歩'、および2)を使用する非同期APIを使用します'Task.Run'の代わりに。 –

答えて

3

まず、イベントハンドラ以外のasync voidは使用しないでください。

第2に、進行状況の更新はIProgress<T>で行う必要があります。これにより、あなたの進捗状況の更新コンシューマであるProgress<T>を使用することができます。これは、スレッド遷移を行います。

第3に、Task.Runの代わりに非同期APIを使用します。あなたはむしろ時代遅れHttpWebRequestの代わりにHttpClientを使用することもできます。

private static readonly HttpClient client = new HttpClient(); 
public async Task DownloadProcedureAsync(long contentLength, IProgress<double> progress) 
{ 
    long totalBytesReceived = 0; 
    int bytesRead = 0; 
    byte[] buffer = new byte[10 * 1024]; 

    using (var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead)) 
    using (var remoteStream= await response.Content.ReadAsStreamAsync()) 
    { 
    while ((bytesRead = await remoteStream.ReadAsync(buffer, 0, buffer.Length)) > 0) 
    { 
     totalBytesReceived += bytesRead; 
     double newProgress = (totalBytesReceived * 100d/contentLength); 
     progress?.Report(newProgress); 
    } 
    } 
} 

使用法:

async void Form1_Load(object sender, EventArgs e) 
{ 
    DownloadManager dm = new DownloadManager("http://download.thinkbroadband.com/20MB.zip", ""); 

    long size = 0; 
    bool res = false; 
    dm.checkUrl(ref size, ref res); 
    var progress = new Progress<double>(p => { Text = e.ToString("0.00"); }); 
    await dm.DownloadProcedureAsync(size, progress); 
} 
関連する問題