Практическое руководство. Фоновая загрузка файла
Обновлен: Ноябрь 2007
Загрузка файла – это обычная задача, и было бы разумным запускать эту потенциально длительную операцию в отдельном потоке. С помощью компонента BackgroundWorker и небольшого фрагмента кода эта задача легко решается.
Пример
В следующем примере кода показано, как использовать компонент BackgroundWorker для загрузки файла XML с URL-адреса. При нажатии на кнопку Загрузить обработчик событий Click вызывает метод RunWorkerAsync компонента BackgroundWorker для запуска операции загрузки. Кнопка отключается во время загрузки и по окончании загрузки снова становится активной. В 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 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());
}
}
Загрузка файла
Файл загружается в рабочем потоке компонента 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();
// 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);
}
Ожидание окончания работы BackgroundWorker
Обработчик событий dowloadButton_Click определяет порядок ожидания завершения асинхронной задачи компонентом BackgroundWorker. При помощи свойства IsBusy можно установить, выполняется ли поток BackgroundWorker. Если код находится в основном потоке пользовательского интерфейса, как в случае с обработчиком событий Click, то для сохранения отклика пользовательского интерфейса следует вызвать метод Application.DoEvents.
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;
}
Отображение результата
Метод backgroundWorker1_RunWorkerCompleted обрабатывает событие RunWorkerCompleted и вызывается по завершении фоновой операции. Сначала, он проверяет свойство AsyncCompletedEventArgs.Error, и если оно равно null – отображает содержимое файла.
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 );
}
}
Компиляция кода
Для этого примера требуются следующие компоненты:
- Ссылки на сборки System.Drawing, System.Windows.Forms и System.Xml.
Дополнительные сведения о построении этого примера из командной строки для Visual Basic или Visual C# см. в разделе Построение из командной строки (Visual Basic) или Построение из командной строки с помощью csc.exe. Можно также построить этот пример в Visual Studio путем вставки кода в новый проект. Дополнительные сведения см. в разделах Практическое руководство. Компиляция и выполнение откомпилированного примера кода формы Windows Forms с помощью Visual Studio и Практическое руководство. Компиляция и выполнение откомпилированного примера кода формы Windows Forms с помощью Visual Studio и Практическое руководство. Компиляция и выполнение откомпилированного примера кода формы Windows Forms с помощью Visual Studio.
Отказоустойчивость
Перед попыткой обращения к свойству RunWorkerCompletedEventArgs.Result или любому другому объекту, который может быть изменен обработчиком событий DoWork, всегда проверяйте свойство AsyncCompletedEventArgs.Error в обработчике событий RunWorkerCompleted.
См. также
Задачи
Практическое руководство. Фоновое выполнение операции
Практическое руководство. Реализация формы, в которой выполняется фоновая операция