C# BackgroundWorker使用教程
背景介绍
在多线程编程中,通常会使用BackgroundWorker
来完成一些后台任务,如文件操作、数据处理等。BackgroundWorker
可以实现在主线程中操作UI元素的同时,后台线程执行繁重的操作,避免了UI线程的阻塞。
安装和引用
在使用BackgroundWorker
之前,需要在项目中引用System.ComponentModel
命名空间。这个命名空间包含了BackgroundWorker
类以及其他与组件(控件)开发相关的类。
using System.ComponentModel;
基本使用
创建并注册事件处理程序
在使用BackgroundWorker
之前,需要在代码中创建并注册事件处理程序。通过事件处理程序可以获得后台线程的状态并做出相应的处理。
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;//设置为支持进度报告
worker.DoWork += worker_DoWork;//注册DoWork事件处理程序
worker.ProgressChanged += worker_ProgressChanged;//注册ProgressChanged事件处理程序
worker.RunWorkerCompleted += worker_RunWorkerCompleted;//注册RunWorkerCompleted事件处理程序
BackgroundWorker
有三个重要的事件处理程序:
DoWork
:指定后台线程要执行的操作。ProgressChanged
:在后台线程执行操作的过程中通知主线程进度状态。RunWorkerCompleted
:后台线程执行操作完成后,在主线程中触发事件。
执行任务
使用RunWorkerAsync()
方法启动后台任务。
worker.RunWorkerAsync(argument);
在RunWorkerAsync()
方法中传递一个可选的参数,这个参数将传递给DoWork
事件处理程序。
实现DoWork事件处理程序
在DoWork
事件处理程序中编写后台线程要执行的操作。这个方法总是在后台线程中执行。
下面是一个示例,在后台线程中计算1到100的和并返回结果。
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
int sum = 0;
for (int i = 1; i <= 100; i++)
{
sum += i;
(sender as BackgroundWorker).ReportProgress(i);//通知主线程进度状态
if ((sender as BackgroundWorker).CancellationPending)//中断任务
{
e.Cancel = true;
return;
}
}
e.Result = sum;//将计算结果传递给RunWorkerCompleted事件处理程序
}
实现ProgressChanged事件处理程序
在ProgressChanged
事件处理程序中更新UI界面的进度信息。
下面是一个示例,将进度信息显示在一个TextBox
控件中。
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
textBox1.Text = e.ProgressPercentage + "%";//更新进度信息
}
实现RunWorkerCompleted事件处理程序
在RunWorkerCompleted
事件处理程序中完成后续操作。
下面是一个示例,将计算结果显示在一个Label
控件中。
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (!e.Cancelled && e.Error == null)//任务完成且没有错误
{
label1.Text = "Sum: " + e.Result;//显示计算结果
}
}
示例1:异步读取文件
下面是一个示例,在后台线程中异步读取文件,并显示读取的文件内容。
private void buttonLoadFile_Click(object sender, EventArgs e)
{
OpenFileDialog dialog = new OpenFileDialog();
dialog.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*";
if (dialog.ShowDialog() == DialogResult.OK)
{
textBoxFile.Text = "Loading...";
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += worker_LoadFile;
worker.RunWorkerCompleted += worker_LoadFileCompleted;
worker.RunWorkerAsync(dialog.FileName);
}
}
private void worker_LoadFile(object sender, DoWorkEventArgs e)
{
string fileName = e.Argument.ToString();
e.Result = File.ReadAllText(fileName);
}
private void worker_LoadFileCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show(e.Error.Message, "Error");
}
else if (!e.Cancelled)
{
textBoxFile.Text = e.Result.ToString();
}
}
示例2:多线程下载文件
下面是一个示例,使用多线程下载文件并显示下载进度。
private void buttonDownload_Click(object sender, EventArgs e)
{
string url = textBoxUrl.Text;
string fileName = Path.GetFileName(url);
WebClient client = new WebClient();
//获取服务器文件大小
long fileSize = -1;
try
{
WebRequest request = WebRequest.Create(url);
request.Method = "HEAD";
WebResponse response = request.GetResponse();
fileSize = response.ContentLength;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error");
return;
}
if (fileSize <= 0)
{
MessageBox.Show("Cannot get file size.", "Error");
return;
}
//开始下载文件
progressBarDownload.Value = 0;
labelDownload.Text = "0%";
buttonDownload.Enabled = false;
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.DoWork += (s, evt) =>
{
try
{
FileStream stream = new FileStream(fileName, FileMode.Create);
long downloadedSize = 0;
int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
Stream responseStream = client.OpenRead(url);
while (true)
{
if (worker.CancellationPending)//中断下载
{
evt.Cancel = true;
stream.Close();
client.CancelAsync();
File.Delete(fileName);
return;
}
int readCount = responseStream.Read(buffer, 0, bufferSize);
if (readCount > 0)
{
stream.Write(buffer, 0, readCount);
downloadedSize += readCount;
int progressPercentage = (int)(downloadedSize * 100 / fileSize);
worker.ReportProgress(progressPercentage);
}
else//下载完成
{
stream.Flush();
stream.Close();
responseStream.Close();
return;
}
}
}
catch (Exception ex)
{
evt.Result = ex.Message;
}
};
worker.ProgressChanged += (s, evt) =>
{
progressBarDownload.Value = evt.ProgressPercentage;
labelDownload.Text = evt.ProgressPercentage + "%";
};
worker.RunWorkerCompleted += (s, evt) =>
{
if (evt.Error != null)
{
MessageBox.Show(evt.Error.Message, "Error");
}
else if (!evt.Cancelled)
{
if (evt.Result != null)
{
MessageBox.Show(evt.Result.ToString(), "Error");
}
else
{
MessageBox.Show("Download complete.", "Info");
}
}
buttonDownload.Enabled = true;
};
worker.RunWorkerAsync();
}
private void buttonCancel_Click(object sender, EventArgs e)
{
backgroundWorker1.CancelAsync();//中断下载
}
结论
BackgroundWorker
是一个非常有用的类,可以在多线程编程中实现UI线程和后台线程之间的无缝协作,避免阻塞UI线程。在实际开发中可以根据具体的需求使用BackgroundWorker
,以提高程序的响应速度和用户体验。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C# BackgroundWorker使用教程 - Python技术站