방법: 백그라운드에서 파일 다운로드
파일 다운로드는 일반 작업이며, 대체로 시간이 많이 걸릴 수 있는 이 작업을 별도 스레드에서 실행하는 데 유용합니다. 매우 적은 양의 코드로 이 작업을 수행려면 BackgroundWorker 구성 요소를 사용합니다.
예제
다음 코드 예제에서는 BackgroundWorker 구성 요소를 사용하여 URL에서 XML 파일을 로드하는 방법을 보여 줍니다. 사용자가 다운로드 단추를 클릭하면 Click 이벤트 처리기가 BackgroundWorker 구성 요소의 RunWorkerAsync 메서드를 호출하여 다운로드 작업을 시작합니다. 다운로드 기간 중에는 단추를 사용할 수 없으며, 다운로드가 완료되면 사용할 수 있습니다. MessageBox는 파일 내용을 표시합니다.
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
// DoWork 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());
}
}
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"
' Required designer variable.
Private components As System.ComponentModel.IContainer = Nothing
' Clean up any resources being used.
' <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
' Required method for Designer support - do not modify
' the contents of this method with the code editor.
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
' The main entry point for the application.
<STAThread()> _
Shared Sub Main()
Application.EnableVisualStyles()
Application.Run(New Form1())
End Sub
End Class
파일 다운로드
DoWork 이벤트 처리기를 실행하는 BackgroundWorker 구성 요소의 작업자 스레드에서 파일이 다운로드됩니다. 이 스레드는 코드에서 RunWorkerAsync 메서드를 호출할 때 시작됩니다.
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 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
BackgroundWorker가 완료될 때까지 대기
downloadButton_Click
이벤트 처리기는 BackgroundWorker 구성 요소가 비동기 작업을 완료할 때까지 기다리는 방법을 보여 줍니다.
애플리케이션에서 이벤트에 응답만 하고 백그라운드 스레드가 완료될 때까지 기다리는 동안 주 스레드에서 작업을 수행하지 않으려는 경우 처리기를 종료합니다.
주 스레드에서 작업을 계속하려는 경우 IsBusy 속성을 사용하여 BackgroundWorker 스레드가 여전히 실행되고 있는지 여부를 확인합니다. 예제에서는 다운로드가 처리되는 동안 진행률 표시줄이 업데이트됩니다. Application.DoEvents 메서드를 호출하여 UI 응답성을 유지해야 합니다.
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 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
결과 표시
backgroundWorker1_RunWorkerCompleted
메서드는 RunWorkerCompleted 이벤트를 처리하며, 백그라운드 작업이 완료될 때 호출됩니다. 이 메서드는 먼저 AsyncCompletedEventArgs.Error 속성을 확인합니다. AsyncCompletedEventArgs.Error가 null
이면 이 메서드는 파일 내용을 표시합니다. 다운로드를 시작할 때 사용할 수 없게 된 다운로드 단추를 사용할 수 있도록 하며 진행률 표시줄을 다시 설정합니다.
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;
}
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
코드 컴파일
이 예제에는 다음 사항이 필요합니다.
- System.Drawing, System.Windows.Forms 및 System.Xml 어셈블리에 대한 참조
강력한 프로그래밍
RunWorkerCompletedEventArgs.Result 속성이나 DoWork 이벤트 처리기의 영향을 받았을 수 있는 다른 개체에 액세스하기 전에 항상 RunWorkerCompleted 이벤트 처리기의 AsyncCompletedEventArgs.Error 속성을 확인합니다.
참고 항목
.NET Desktop feedback