共用方式為


HOW TO:在背景中下載檔案

下載檔案是一種常見的工作,而以個別執行緒來執行這項可能會很耗時的作業,通常會很有幫助。 您可以使用 BackgroundWorker 元件,以少量的程式碼達成這個工作。

範例

下列程式碼範例會示範如何使用 BackgroundWorker 元件從一個 URL 載入 XML 檔案。 當使用者按下 [下載] 按鈕時,Click 事件處理常式會呼叫 BackgroundWorker 元件的 RunWorkerAsync 方法以啟動下載作業。 這個按鈕在下載期間會先停用,待下載完成之後再行啟用。 MessageBox 會顯示檔案的內容。

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

下載檔案

檔案會在 BackgroundWorker 元件的背景工作執行緒中下載,這個執行緒會執行 DoWork 事件處理常式。 當您的程式碼呼叫 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");
}

等候 BackgroundWorker 完成

downloadButton_Click 事件處理常式示範了如何等候一個 BackgroundWorker 元件完成其非同步工作。

如果您只想讓應用程式回應事件,但是不要在等待幕後執行緒完成期間於主執行緒中執行任何工作,則只要結束處理常式即可。

如果您想要在主執行緒中繼續執行工作,請使用 IsBusy 屬性判斷 BackgroundWorker 執行緒是否仍在執行。 下列範例中會使用一個進度列,隨下載處理過程更新進度顯示。 請務必呼叫 Application.DoEvents 方法來保持 UI 正常回應。

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

顯示結果

backgroundWorker1_RunWorkerCompleted 方法會處理 RunWorkerCompleted 事件,當背景作業完成時即會呼叫此方法。 這個方法會先檢查 AsyncCompletedEventArgs.Error 屬性。 如果 AsyncCompletedEventArgs.Error 是 null,這個方法便會顯示檔案的內容, 然後啟用已在下載開始時停用的下載按鈕,並重設進度列。

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

編譯程式碼

這個範例需要:

  • System.Drawing、System.Windows.Forms 和 System.Xml 組件的參考。

如需從 Visual Basic 或 Visual C# 的命令列建置這個範例的詳細資訊,請參閱從命令列建置 (Visual Basic)使用 csc.exe 建置命令列。 您也可以透過將程式碼貼入新的專案,在 Visual Studio 中建置此範例。 如需詳細資訊,請參閱HOW TO:使用 Visual Studio 編譯及執行完整的 Windows Form 程式碼範例HOW TO:使用 Visual Studio 編譯及執行完整的 Windows Form 程式碼範例HOW TO:使用 Visual Studio 編譯及執行完整的 Windows Form 程式碼範例HOW TO:使用 Visual Studio 編譯及執行完整的 Windows Form 程式碼範例如何:使用 Visual Studio 編譯及執行完整的 Windows Form 程式碼範例.

穩固程式設計

在嘗試存取 RunWorkerCompletedEventArgs.Result 屬性或任何其他可能受 DoWork 事件處理常式影響的物件之前,永遠先檢查 RunWorkerCompleted 事件處理常式中的 AsyncCompletedEventArgs.Error 屬性。

請參閱

工作

HOW TO:在背景執行作業

HOW TO:實作使用背景作業的表單

參考

BackgroundWorker