web-dev-qa-db-fra.com

Téléchargement de fichier asynchrone avec barre de progression

J'essaie de modifier la progression d'une barre de progression à mesure que la progression de WebClient change. Ce code télécharge encore le fichier mais quand j'appelle startDownload(), la fenêtre se fige pendant le téléchargement du fichier. J'aimerais que l'utilisateur puisse voir l'évolution de la progression lorsque l'écran de démarrage se charge. Existe-t-il un moyen de résoudre ce problème afin que l'utilisateur puisse voir la progression du changement progressBar2?

private void startDownload()
{
    WebClient client = new WebClient();
    client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
    client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
    client.DownloadFileAsync(new Uri("http://joshua-ferrara.com/luahelper/lua.syn"), @"C:\LUAHelper\Syntax Files\lua.syn");
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
    double bytesIn = double.Parse(e.BytesReceived.ToString());
    double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
    double percentage = bytesIn / totalBytes * 100;
    label2.Text = "Downloaded " + e.BytesReceived + " of " + e.TotalBytesToReceive;
    progressBar1.Value = int.Parse(Math.Truncate(percentage).ToString());
}
void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
    label2.Text = "Completed";
}
19
Joshua Ferrara

Vous devez appeler startDownload() à partir du fil de l'interface utilisateur. L'idée même de WebClient.DownloadFileAsync() est qu'il créera automatiquement un thread de travail sans bloquer le thread appelant. Dans startDownload(), vous avez spécifié des rappels qui modifient des contrôles qui, je suppose, ont été créés par le thread d'interface utilisateur. Ainsi, si vous appelez startDownload() à partir d'un thread d'arrière-plan, cela posera des problèmes, car un thread ne peut modifier que les éléments d'interface utilisateur qu'il a créés.

Il est censé fonctionner comme suit: vous appelez startDownload() à partir du thread d'interface utilisateur, startDownload() lorsque vous l'avez défini, il configure les rappels d'événement gérés par le thread d'interface utilisateur. Il commence alors le téléchargement de manière asynchrone et revient immédiatement. Le thread d'interface utilisateur sera averti lorsque la progression changera et le code responsable de la mise à jour du contrôle de barre de progression s'exécutera sur le thread d'interface utilisateur, et il ne devrait y avoir aucun problème.

13
Bojin Li

Le thread d'interface utilisateur sera gelé lorsque vous cliquez sur startDownload (). Si vous ne voulez pas que le formulaire soit gelé, utilisez startDownload () dans un autre thread et effectuez la mise à jour en cours de mise à jour dans plusieurs threads .

private void startDownload()
{
    Thread thread = new Thread(() => {
          WebClient client = new WebClient();
          client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
          client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
          client.DownloadFileAsync(new Uri("http://joshua-ferrara.com/luahelper/lua.syn"), @"C:\LUAHelper\Syntax Files\lua.syn");
    });
    thread.Start();
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
    this.BeginInvoke((MethodInvoker) delegate {
        double bytesIn = double.Parse(e.BytesReceived.ToString());
        double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
        double percentage = bytesIn / totalBytes * 100;
        label2.Text = "Downloaded " + e.BytesReceived + " of " + e.TotalBytesToReceive;
        progressBar1.Value = int.Parse(Math.Truncate(percentage).ToString());
    });
}
void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
    this.BeginInvoke((MethodInvoker) delegate {
         label2.Text = "Completed";
    }); 
}

Lisez-en davantage sur Google comme ceci http://msdn.Microsoft.com/en-us/library/ms951089.aspx

-Fixe manquant fermer); à la déclaration bgThread

21
Peter PAD

Je crois que cet article vous mènera dans la bonne direction http://www.dreamincode.net/forums/topic/115491-download-file-asynchronously-with-progressbar/

Et dans cet article MSDN http://msdn.Microsoft.com/en-us/library/ms229675.aspx explique comment "Le fichier est téléchargé sur le thread de travail du composant BackgroundWorker, qui exécute le gestionnaire d'événements DoWork. le thread commence lorsque votre code appelle la méthode RunWorkerAsync. " 

1
Stephen Tetreault
 public class ProgressEventArgsEx
{
    public int Percentage { get; set; }
    public string Text { get; set; }
}
public async static Task<string> DownloadStraingAsyncronous(string url, IProgress<ProgressEventArgsEx> progress)
{
    WebClient c = new WebClient();
    byte[] buffer = new byte[1024];
    var bytes = 0;
    var all = String.Empty;
    using (var stream = await c.OpenReadTaskAsync(url))
    {
        int total = -1;
        Int32.TryParse(c.ResponseHeaders[HttpRequestHeader.ContentLength], out total);
        for (; ; )
        {
            int len = await stream.ReadAsync(buffer, 0, buffer.Length);
            if (len == 0)
                break;
            string text = c.Encoding.GetString(buffer, 0, len);

            bytes += len;
            all += text;
            if (progress != null)
            {
                var args = new ProgressEventArgsEx();
                args.Percentage = (total <= 0 ? 0 : (100 * bytes) / total);
                progress.Report(args);
            }
        }
    }
    return all;
}
// Sample
private async void Bttn_Click(object sender, RoutedEventArgs e)
{
    //construct Progress<T>, passing ReportProgress as the Action<T> 
    var progressIndicator = new Progress<ProgressEventArgsEx>(ReportProgress);
    await TaskLoader.DownloadStraingAsyncronous(tbx.Text, progressIndicator);
}
private void ReportProgress(ProgressEventArgsEx args)
{
    this.statusText.Text = args.Text + " " + args.Percentage;
}
0
guest