Definir o estado do usuário quando o download de forma assíncrona
Pergunta
VS 2008 SP1
Eu estou usando o clicent web para baixar alguns arquivos de forma assíncrona.
Eu tenho 5 arquivos para download.
No entanto, eu quero acompanhar cada download e pretende definir o estado do usuário como o nome do arquivo, assim, no ProgressCompletedEvent posso verificar o estado do usuário para ver qual arquivo foi concluída?
Ele é um trecho de código curto do que estou tentando fazer.
// 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());
}
Solução
Você pode passar qualquer objeto como o terceira argumento para a chamada DownloadFileAsync (), e você vai obtê-lo de volta como o userState. No seu caso, você poderia simplesmente passar o seu nome de arquivo.
Outras dicas
Como sobre algo como isto:
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);
}
No seu código de chamada, você poderia, então, ter algum código como este:
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);
Se você não se importa sobre o que torna muito reutilizável, você pode realmente apenas cavar o passado em funções todos juntos e escrever as expressões lambda em linha reta em seu código:
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);
}
Chamado duas vezes, isso vai lhe dar someting saída como esta ??p>
/ path / to / file1: 265/265 bytes recebidos (100%)
/ Path / to / file1: Concluído
/ / A / arq2 caminho: 2134/2134 bytes recebidos (100%)
/ Path / to / file2: Concluído