tags:

views:

560

answers:

2

VS 2008 SP1

I am using the web clicent to download some files asynchronously.

I have 5 files to download.

However, I want to monitor each download and want to set the user state as the name of the file, so in the ProgressCompletedEvent I can check the user state to see which file has completed?

He is a short code snippet of what I am trying to do.

// This function will be called for each file that is going to be downloaded.
// is there a way I can set the user state so I know that the download 
// has been completed 
// for that file, in the DownloadFileCompleted Event? 
private void DownloadSingleFile()
{
    if (!wb.IsBusy)
    {        
        //  Set user state here       
        wb.DownloadFileAsync(new Uri(downloadUrl), installationPath);
    }
}


void wb_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
    Console.WriteLine("File userstate: [ " + e.UserState + " ]");   
}

void wb_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
    Console.WriteLine("File userstate: [ " + e.UserState + " ]");   

    double bytesIn = double.Parse(e.BytesReceived.ToString());
    double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
    double percentage = bytesIn / totalBytes * 100;

    progressBar1.Value = int.Parse(Math.Truncate(percentage).ToString());

}
+2  A: 

You can pass any object as the third argument to the DownloadFileAsync() call, and you'll get it back as the userState. In your case, you could simply pass your filename.

Paul-Jan
+1  A: 

How about something like this:

private void BeginDownload(
 string uriString,
 string localFile,
 Action<string, DownloadProgressChangedEventArgs> onProgress,
 Action<string, AsyncCompletedEventArgs> onComplete)
{
 WebClient webClient = new WebClient();

 webClient.DownloadProgressChanged +=
  (object sender, DownloadProgressChangedEventArgs e) =>
   onProgress(localFile, e);

 webClient.DownloadFileCompleted +=
  (object sender, AsyncCompletedEventArgs e) =>
   onComplete(localFile, e);

 webClient.DownloadFileAsync(new Uri(uriString), localFile);
}

In your calling code, you could then have some code like this:

Action<string, DownloadProgressChangedEventArgs> onProgress =
 (string localFile, DownloadProgressChangedEventArgs e) =>
 {
  Console.WriteLine("{0}: {1}/{2} bytes received ({3}%)",
   localFile, e.BytesReceived,
   e.TotalBytesToReceive, e.ProgressPercentage);
 };

Action<string, AsyncCompletedEventArgs> onComplete =
 (string localFile, AsyncCompletedEventArgs e) =>
 {
  Console.WriteLine("{0}: {1}", localFile,
   e.Error != null ? e.Error.Message : "Completed");
 };

downloader.BeginDownload(
 @"http://url/to/file",
 @"/local/path/to/file",
 onProgress, onComplete);

If you don't mind about making it too reusable, you can actually just ditch the passed in functions all together and write the lambda expressions straight in your code:

private void BeginDownload(string uriString, string localFile)
{
 WebClient webClient = new WebClient();

 webClient.DownloadProgressChanged +=
  (object sender, DownloadProgressChangedEventArgs e) =>
   Console.WriteLine("{0}: {1}/{2} bytes received ({3}%)",
    localFile, e.BytesReceived,
    e.TotalBytesToReceive, e.ProgressPercentage);

 webClient.DownloadFileCompleted +=
  (object sender, AsyncCompletedEventArgs e) =>
   Console.WriteLine("{0}: {1}", localFile,
    e.Error != null ? e.Error.Message : "Completed");

 webClient.DownloadFileAsync(new Uri(uriString), localFile);
}

Called twice, this will give you output someting like this

/path/to/file1: 265/265 bytes received (100%)
/path/to/file1: Completed
/path/to/file2: 2134/2134 bytes received (100%)
/path/to/file2: Completed

IRBMe