Comment : télécharger un fichier en arrière-plan

Le téléchargement d'un fichier est une tâche courante, et il est souvent utile d'exécuter cette opération susceptible de prendre du temps sur un thread séparé. Utilisez le composant BackgroundWorker pour effectuer cette tâche avec très peu de code.

Exemple

L'exemple de code suivant montre comment utiliser un composant BackgroundWorker pour charger un fichier XML à partir d'une URL. Lorsque l'utilisateur clique sur le bouton Télécharger, le gestionnaire d'événements Click appelle la méthode RunWorkerAsync d'un composant BackgroundWorker pour démarrer l'opération de téléchargement. Le bouton est désactivé pendant la durée du téléchargement, et réactivé à la fin du téléchargement. Une MessageBox affiche le contenu du fichier.

Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Drawing
Imports System.Threading
Imports System.Windows.Forms
Imports System.Xml

Public Class Form1
    Inherits Form

    Private WithEvents downloadButton As Button
    Private WithEvents progressBar1 As ProgressBar
    Private WithEvents backgroundWorker1 As BackgroundWorker
    Private document As XmlDocument = Nothing

    Public Sub New()
        InitializeComponent()
        Me.backgroundWorker1 = New System.ComponentModel.BackgroundWorker()
    End Sub

    Private Sub downloadButton_Click( _
        ByVal sender As Object, _
        ByVal e As EventArgs) _
        Handles downloadButton.Click

        ' Start the download operation in the background.
        Me.backgroundWorker1.RunWorkerAsync()

        ' Disable the button for the duration of the download.
        Me.downloadButton.Enabled = False

        ' Once you have started the background thread you 
        ' can exit the handler and the application will 
        ' wait until the RunWorkerCompleted event is raised.

        ' If you want to do something else in the main thread,
        ' such as update a progress bar, you can do so in a loop 
        ' while checking IsBusy to see if the background task is
        ' still running.
        While Me.backgroundWorker1.IsBusy
            progressBar1.Increment(1)
            ' Keep UI messages moving, so the form remains 
            ' responsive during the asynchronous operation.
            Application.DoEvents()
        End While
    End Sub

    Private Sub backgroundWorker1_DoWork( _
        ByVal sender As Object, _
        ByVal e As DoWorkEventArgs) _
        Handles backgroundWorker1.DoWork

        document = New XmlDocument()

        ' Replace this file name with a valid file name.
        document.Load("http://www.tailspintoys.com/sample.xml")

        ' Uncomment the following line to
        ' simulate a noticeable latency.
        'Thread.Sleep(5000);
    End Sub

    Private Sub backgroundWorker1_RunWorkerCompleted( _
        ByVal sender As Object, _
        ByVal e As RunWorkerCompletedEventArgs) _
        Handles backgroundWorker1.RunWorkerCompleted

        ' Set progress bar to 100% in case it isn't already there.
        progressBar1.Value = 100

        If e.Error Is Nothing Then
            MessageBox.Show(document.InnerXml, "Download Complete")
        Else
            MessageBox.Show("Failed to download file", "Download failed", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End If

        ' Enable the download button and reset the progress bar.
        Me.downloadButton.Enabled = True
        progressBar1.Value = 0
    End Sub

#Region "Windows Form Designer generated code"
    ' <summary>
    ' Required designer variable.
    ' </summary>
    Private components As System.ComponentModel.IContainer = Nothing

    ' <summary>
    ' Clean up any resources being used.
    ' </summary>
    ' <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing AndAlso (components IsNot Nothing) Then
            components.Dispose()
        End If
        MyBase.Dispose(disposing)
    End Sub

    ' <summary>
    ' Required method for Designer support - do not modify
    ' the contents of this method with the code editor.
    ' </summary>
    Private Sub InitializeComponent()
        Me.downloadButton = New System.Windows.Forms.Button
        Me.progressBar1 = New System.Windows.Forms.ProgressBar
        Me.SuspendLayout()
        '
        'downloadButton
        '
        Me.downloadButton.Location = New System.Drawing.Point(12, 12)
        Me.downloadButton.Name = "downloadButton"
        Me.downloadButton.Size = New System.Drawing.Size(100, 23)
        Me.downloadButton.TabIndex = 0
        Me.downloadButton.Text = "Download file"
        Me.downloadButton.UseVisualStyleBackColor = True
        '
        'progressBar1
        '
        Me.progressBar1.Location = New System.Drawing.Point(12, 50)
        Me.progressBar1.Name = "progressBar1"
        Me.progressBar1.Size = New System.Drawing.Size(100, 26)
        Me.progressBar1.TabIndex = 1
        '
        'Form1
        '
        Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
        Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
        Me.ClientSize = New System.Drawing.Size(136, 104)
        Me.Controls.Add(Me.downloadButton)
        Me.Controls.Add(Me.progressBar1)
        Me.Name = "Form1"
        Me.Text = "Form1"
        Me.ResumeLayout(False)

    End Sub

#End Region
End Class


Public Class Program

    ' <summary>
    ' The main entry point for the application.
    ' </summary>
    <STAThread()> _
    Shared Sub Main()
        Application.EnableVisualStyles()
        Application.Run(New Form1())
    End Sub
End Class
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
using System.Xml;

public class Form1 : Form
{
    private BackgroundWorker backgroundWorker1;
    private Button downloadButton;
    private ProgressBar progressBar1;
    private XmlDocument document = null;

    public Form1()
    {
        InitializeComponent();

        // Instantiate BackgroundWorker and attach handlers to its
        // DowWork and RunWorkerCompleted events.
        backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
        backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
        backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);
    }

    private void downloadButton_Click(object sender, EventArgs e)
    {
        // Start the download operation in the background.
        this.backgroundWorker1.RunWorkerAsync();

        // Disable the button for the duration of the download.
        this.downloadButton.Enabled = false;

        // Once you have started the background thread you 
        // can exit the handler and the application will 
        // wait until the RunWorkerCompleted event is raised.

        // Or if you want to do something else in the main thread,
        // such as update a progress bar, you can do so in a loop 
        // while checking IsBusy to see if the background task is
        // still running.

        while (this.backgroundWorker1.IsBusy)
        {
            progressBar1.Increment(1);
            // Keep UI messages moving, so the form remains 
            // responsive during the asynchronous operation.
            Application.DoEvents();
        }
    }

    private void backgroundWorker1_DoWork(
        object sender,
        DoWorkEventArgs e)
    {
        document = new XmlDocument();

        // Uncomment the following line to
        // simulate a noticeable latency.
        //Thread.Sleep(5000);

        // Replace this file name with a valid file name.
        document.Load(@"http://www.tailspintoys.com/sample.xml");
    }

    private void backgroundWorker1_RunWorkerCompleted(
        object sender,
        RunWorkerCompletedEventArgs e)
    {
        // Set progress bar to 100% in case it's not already there.
        progressBar1.Value = 100;

        if (e.Error == null)
        {
            MessageBox.Show(document.InnerXml, "Download Complete");
        }
        else
        {
            MessageBox.Show(
                "Failed to download file",
                "Download failed",
                MessageBoxButtons.OK,
                MessageBoxIcon.Error);
        }

        // Enable the download button and reset the progress bar.
        this.downloadButton.Enabled = true;
        progressBar1.Value = 0;
    }

    #region Windows Form Designer generated code

    /// <summary>
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.IContainer components = null;

    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    /// <summary>
    /// Required method for Designer support
    /// </summary>
    private void InitializeComponent()
    {
        this.downloadButton = new System.Windows.Forms.Button();
        this.progressBar1 = new System.Windows.Forms.ProgressBar();
        this.SuspendLayout();
        // 
        // downloadButton
        // 
        this.downloadButton.Location = new System.Drawing.Point(12, 12);
        this.downloadButton.Name = "downloadButton";
        this.downloadButton.Size = new System.Drawing.Size(100, 23);
        this.downloadButton.TabIndex = 0;
        this.downloadButton.Text = "Download file";
        this.downloadButton.UseVisualStyleBackColor = true;
        this.downloadButton.Click += new System.EventHandler(this.downloadButton_Click);
        // 
        // progressBar1
        // 
        this.progressBar1.Location = new System.Drawing.Point(12, 50);
        this.progressBar1.Name = "progressBar1";
        this.progressBar1.Size = new System.Drawing.Size(100, 26);
        this.progressBar1.TabIndex = 1;
        // 
        // Form1
        // 
        this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.ClientSize = new System.Drawing.Size(133, 104);
        this.Controls.Add(this.progressBar1);
        this.Controls.Add(this.downloadButton);
        this.Name = "Form1";
        this.Text = "Form1";
        this.ResumeLayout(false);

    }

    #endregion
}

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.Run(new Form1());
    }
}

Téléchargement du fichier

Le fichier est téléchargé sur le thread de travail du composant BackgroundWorker, qui exécute le gestionnaire d'événements DoWork. Ce thread démarre lorsque votre code appelle la méthode RunWorkerAsync.

Private Sub backgroundWorker1_DoWork( _
    ByVal sender As Object, _
    ByVal e As DoWorkEventArgs) _
    Handles backgroundWorker1.DoWork

    document = New XmlDocument()

    ' Replace this file name with a valid file name.
    document.Load("http://www.tailspintoys.com/sample.xml")

    ' Uncomment the following line to
    ' simulate a noticeable latency.
    'Thread.Sleep(5000);
End Sub
private void backgroundWorker1_DoWork(
    object sender,
    DoWorkEventArgs e)
{
    document = new XmlDocument();

    // Uncomment the following line to
    // simulate a noticeable latency.
    //Thread.Sleep(5000);

    // Replace this file name with a valid file name.
    document.Load(@"http://www.tailspintoys.com/sample.xml");
}

Attente de la fin d'un composant BackgroundWorker

Le gestionnaire d'événements downloadButton_Click montre comment attendre qu'un composant BackgroundWorker ait terminé sa tâche asynchrone.

Si vous souhaitez uniquement que l'application réponde aux événements et ne voulez pas exécuter de tâche dans le thread principal en attendant que le thread d'arrière-plan se termine, quittez simplement le gestionnaire.

Si vous souhaitez continuer à travailler dans le thread principal, utilisez la propriété IsBusy pour déterminer si le thread BackgroundWorker est toujours en cours d'exécution. Dans l'exemple, une barre de progression est mise à jour pendant l'exécution du téléchargement. Veillez à appeler la méthode Application.DoEvents pour que l'interface utilisateur reste réactive.

Private Sub downloadButton_Click( _
    ByVal sender As Object, _
    ByVal e As EventArgs) _
    Handles downloadButton.Click

    ' Start the download operation in the background.
    Me.backgroundWorker1.RunWorkerAsync()

    ' Disable the button for the duration of the download.
    Me.downloadButton.Enabled = False

    ' Once you have started the background thread you 
    ' can exit the handler and the application will 
    ' wait until the RunWorkerCompleted event is raised.

    ' If you want to do something else in the main thread,
    ' such as update a progress bar, you can do so in a loop 
    ' while checking IsBusy to see if the background task is
    ' still running.
    While Me.backgroundWorker1.IsBusy
        progressBar1.Increment(1)
        ' Keep UI messages moving, so the form remains 
        ' responsive during the asynchronous operation.
        Application.DoEvents()
    End While
End Sub
private void downloadButton_Click(object sender, EventArgs e)
{
    // Start the download operation in the background.
    this.backgroundWorker1.RunWorkerAsync();

    // Disable the button for the duration of the download.
    this.downloadButton.Enabled = false;

    // Once you have started the background thread you 
    // can exit the handler and the application will 
    // wait until the RunWorkerCompleted event is raised.

    // Or if you want to do something else in the main thread,
    // such as update a progress bar, you can do so in a loop 
    // while checking IsBusy to see if the background task is
    // still running.

    while (this.backgroundWorker1.IsBusy)
    {
        progressBar1.Increment(1);
        // Keep UI messages moving, so the form remains 
        // responsive during the asynchronous operation.
        Application.DoEvents();
    }
}

Affichage du résultat

La méthode backgroundWorker1_RunWorkerCompleted gère l'événement RunWorkerCompleted et est appelée lorsque l'opération en arrière-plan est terminée. Cette méthode vérifie d'abord la propriété AsyncCompletedEventArgs.Error. Si AsyncCompletedEventArgs.Error est null, la méthode affiche le contenu du fichier. Elle active ensuite le bouton de téléchargement, qui était désactivé lorsque le téléchargement a commencé, et réinitialise la barre de progression.

Private Sub backgroundWorker1_RunWorkerCompleted( _
    ByVal sender As Object, _
    ByVal e As RunWorkerCompletedEventArgs) _
    Handles backgroundWorker1.RunWorkerCompleted

    ' Set progress bar to 100% in case it isn't already there.
    progressBar1.Value = 100

    If e.Error Is Nothing Then
        MessageBox.Show(document.InnerXml, "Download Complete")
    Else
        MessageBox.Show("Failed to download file", "Download failed", MessageBoxButtons.OK, MessageBoxIcon.Error)
    End If

    ' Enable the download button and reset the progress bar.
    Me.downloadButton.Enabled = True
    progressBar1.Value = 0
End Sub
private void backgroundWorker1_RunWorkerCompleted(
    object sender,
    RunWorkerCompletedEventArgs e)
{
    // Set progress bar to 100% in case it's not already there.
    progressBar1.Value = 100;

    if (e.Error == null)
    {
        MessageBox.Show(document.InnerXml, "Download Complete");
    }
    else
    {
        MessageBox.Show(
            "Failed to download file",
            "Download failed",
            MessageBoxButtons.OK,
            MessageBoxIcon.Error);
    }

    // Enable the download button and reset the progress bar.
    this.downloadButton.Enabled = true;
    progressBar1.Value = 0;
}

Compilation du code

Cet exemple requiert l'élément suivant :

  • Références aux assemblys System.Drawing, System.Windows.Forms et System.Xml.

Pour plus d'informations sur la génération de cet exemple à partir de la ligne de commande pour Visual Basic ou Visual C#, consultez Génération à partir de la ligne de commande (Visual Basic) ou Génération à partir de la ligne de commande avec csc.exe. Vous pouvez aussi générer cet exemple dans Visual Studio en collant le code dans un nouveau projet. Pour plus d'informations, consultez Comment : compiler et exécuter un exemple complet de code Windows Forms à l'aide de Visual Studio et Comment : compiler et exécuter un exemple complet de code Windows Forms à l'aide de Visual Studio et Comment : compiler et exécuter un exemple complet de code Windows Forms à l'aide de Visual Studio et Comment : compiler et exécuter un exemple complet de code Windows Forms à l'aide de Visual Studio et Comment : compiler et exécuter un exemple complet de code Windows Forms à l'aide de Visual Studio.

Programmation fiable

Vérifiez toujours la propriété AsyncCompletedEventArgs.Error de votre gestionnaire d'événements RunWorkerCompleted avant d'essayer d'accéder à la propriété RunWorkerCompletedEventArgs.Result ou à tout autre objet ayant pu être affecté par le gestionnaire d'événements DoWork.

Voir aussi

Tâches

Comment : exécuter une opération en arrière-plan

Comment : implémenter un formulaire qui utilise une opération d'arrière-plan

Référence

BackgroundWorker