How to: Download a File in the Background

Downloading a file is a common task, and it is often useful to run this potentially time-consuming operation on a separate thread. Use the BackgroundWorker component to accomplish this task with very little code.

Example

The following code example demonstrates how to use a BackgroundWorker component to load an XML file from a URL. When the user clicks the Download button, the Click event handler calls the RunWorkerAsync method of a BackgroundWorker component to start the download operation. The button is disabled for the duration of the download, and then enabled when the download is complete. A MessageBox displays the contents of the file.

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 backgroundWorker1 As BackgroundWorker
   Private WithEvents dowloadButton As Button
   Private document As XmlDocument = Nothing
   
   
   Public Sub New()
      InitializeComponent()
    End Sub
   
    Private Sub dowloadButton_Click( _
    ByVal sender As Object, _
    ByVal e As EventArgs) _
    Handles dowloadButton.Click

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

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

        ' Wait for the BackgroundWorker to finish the download.
        While Me.backgroundWorker1.IsBusy
            ' Keep UI messages moving, so the form remains 
            ' responsive during the asynchronous operation.
            Application.DoEvents()
        End While

        ' The download is done, so enable the button.
        Me.dowloadButton.Enabled = True
    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(sender As Object, e As RunWorkerCompletedEventArgs) Handles backgroundWorker1.RunWorkerCompleted
      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
    End Sub

    ' <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(disposing As Boolean)
      If disposing AndAlso (components IsNot Nothing) Then
         components.Dispose()
      End If
      MyBase.Dispose(disposing)
    End Sub
   
   #Region "Windows Form Designer generated code"
   
   
    ' <summary>
    ' Required method for Designer support - do not modify
    ' the contents of this method with the code editor.
    ' </summary>
   Private Sub InitializeComponent()
      Me.backgroundWorker1 = New System.ComponentModel.BackgroundWorker()
      Me.dowloadButton = New System.Windows.Forms.Button()
      Me.SuspendLayout()
      ' 
      ' backgroundWorker1
      ' 
      ' 
      ' dowloadButton
      ' 
      Me.dowloadButton.Location = New System.Drawing.Point(12, 12)
      Me.dowloadButton.Name = "dowloadButton"
      Me.dowloadButton.Size = New System.Drawing.Size(75, 23)
      Me.dowloadButton.TabIndex = 0
      Me.dowloadButton.Text = "Download file"
      Me.dowloadButton.UseVisualStyleBackColor = True
      ' 
      ' Form1
      ' 
      Me.AutoScaleDimensions = New System.Drawing.SizeF(6F, 13F)
      Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
      Me.ClientSize = New System.Drawing.Size(104, 54)
      Me.Controls.Add(dowloadButton)
      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 dowloadButton;
    private XmlDocument document = null;

    public Form1()
    {
        InitializeComponent();
    }

    private void dowloadButton_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.dowloadButton.Enabled = false;

        // Wait for the BackgroundWorker to finish the download.
        while (this.backgroundWorker1.IsBusy)
        {
            // Keep UI messages moving, so the form remains 
            // responsive during the asynchronous operation.
            Application.DoEvents();
        }

        // The download is done, so enable the button.
        this.dowloadButton.Enabled = true;
    }

    private void backgroundWorker1_DoWork(
        object sender, 
        DoWorkEventArgs e)
    {
        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);
    }

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

    /// <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);
    }

    #region Windows Form Designer generated code

    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
        this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
        this.dowloadButton = new System.Windows.Forms.Button();
        this.SuspendLayout();
        // 
        // backgroundWorker1
        // 
        this.backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
        this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);
        // 
        // dowloadButton
        // 
        this.dowloadButton.Location = new System.Drawing.Point(12, 12);
        this.dowloadButton.Name = "dowloadButton";
        this.dowloadButton.Size = new System.Drawing.Size(75, 23);
        this.dowloadButton.TabIndex = 0;
        this.dowloadButton.Text = "Download file";
        this.dowloadButton.UseVisualStyleBackColor = true;
        this.dowloadButton.Click += new System.EventHandler(this.dowloadButton_Click);
        // 
        // Form1
        // 
        this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.ClientSize = new System.Drawing.Size(104, 54);
        this.Controls.Add(this.dowloadButton);
        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());
    }
}

Downloading the file

The file is downloaded on the BackgroundWorker component's worker thread, which runs the DoWork event handler. This thread starts when your code calls the RunWorkerAsync method.

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();

    // 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);
}

Waiting for a BackgroundWorker to finish

The dowloadButton_Click event handler demonstrates how to wait for a BackgroundWorker component to finish its asynchronous task. Use the IsBusy property to determine if the BackgroundWorker thread is still running. If your code is on the main UI thread, as is the case with the Click event handler, be sure to call the System.Windows.Forms.Application.DoEvents method to keep the UI responsive.

Private Sub dowloadButton_Click( _
ByVal sender As Object, _
ByVal e As EventArgs) _
Handles dowloadButton.Click

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

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

    ' Wait for the BackgroundWorker to finish the download.
    While Me.backgroundWorker1.IsBusy
        ' Keep UI messages moving, so the form remains 
        ' responsive during the asynchronous operation.
        Application.DoEvents()
    End While

    ' The download is done, so enable the button.
    Me.dowloadButton.Enabled = True
End Sub
private void dowloadButton_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.dowloadButton.Enabled = false;

    // Wait for the BackgroundWorker to finish the download.
    while (this.backgroundWorker1.IsBusy)
    {
        // Keep UI messages moving, so the form remains 
        // responsive during the asynchronous operation.
        Application.DoEvents();
    }

    // The download is done, so enable the button.
    this.dowloadButton.Enabled = true;
}

Displaying the result

The backgroundWorker1_RunWorkerCompleted method handles the RunWorkerCompleted event and is called when the background operation is completed. It first checks the System.ComponentModel.AsyncCompletedEventArgs.Error property, and if this is null, it displays the contents of the file.

Private Sub backgroundWorker1_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles backgroundWorker1.RunWorkerCompleted
   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
 End Sub
private void backgroundWorker1_RunWorkerCompleted(
    object sender, 
    RunWorkerCompletedEventArgs e)
{
    if (e.Error == null)
    {
        MessageBox.Show(document.InnerXml, "Download Complete");
    }
    else
    {
        MessageBox.Show(
            "Failed to download file", 
            "Download failed", 
            MessageBoxButtons.OK, 
            MessageBoxIcon.Error );
    }
}

Compiling the Code

This example requires:

  • References to the System.Drawing, System.Windows.Forms, and System.Xml assemblies.

For information about building this example from the command line for Visual Basic or Visual C#, see Building from the Command Line (Visual Basic) or Command-Line Building. You can also build this example in Visual Studio by pasting the code into a new project. How to: Compile and Run a Complete Windows Forms Code Example Using Visual Studio
How to: Compile and Run a Complete Windows Forms Code Example Using Visual Studio
How to: Compile and Run a Complete Windows Forms Code Example Using Visual Studio
How to: Compile and Run a Complete Windows Forms Code Example Using Visual Studio

Robust Programming

Always check the System.ComponentModel.AsyncCompletedEventArgs.Error property in your RunWorkerCompleted event handler before attempting to access the System.ComponentModel.RunWorkerCompletedEventArgs.Result property or any other object that may have been affected by the DoWork event handler.

See Also

Tasks

How to: Run an Operation in the Background
How to: Implement a Form That Uses a Background Operation

Reference

BackgroundWorker