C# BackgroundWorker使用教程

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技术站

(0)
上一篇 2023年5月15日
下一篇 2023年5月15日

相关文章

  • 浅谈C#中的委托、事件与异步

    浅谈C#中的委托、事件与异步攻略 委托 在 C# 中,委托是一个类,它可以封装一个或多个方法。委托是作为参数传递的。通过将方法指定为委托,可以将方法传递给其他方法。这些方法都以相同的委托类型作为参数和返回类型。 声明一个委托: delegate void MyDelegate(string message); 使用委托: public static void…

    C# 2023年6月6日
    00
  • C# 限制输入为字母或数字以及长度

    日常开发过程中,验证字符的合法性一直是一个必不可少的步骤,以前都是在用户输入完再做判断,不仅麻烦在不符合标准的时候还要提示用户修改,体验很差,为什么不在输入的时候加以限制呢? 以 Winform的TextBox控件为例,这里提供两种方案: 通过字符匹配 正则表达式 在用户输入时限制,所以选用KeyPress事件。 字符匹配 private void txt_…

    C# 2023年4月19日
    00
  • C#调用存储过程详解(带返回值、参数输入输出等)

    介绍 在使用C#开发的过程中,经常需要调用存储过程来完成某些任务,比如从数据库中获取数据或者执行一些复杂的数据处理操作。本文将详细介绍C#调用存储过程的方法,包括如何传入参数、传递多个参数、以及如何获取存储过程的返回值。 调用带参数的存储过程 首先,我们需要连接到数据库。以使用SQL Server为例: using System.Data.SqlClient…

    C# 2023年5月15日
    00
  • 如何在 .NET Core WebApi 中处理 MultipartFormDataContent

    最近在对某个后端服务做 .NET Core 升级时,里面使用了多处处理 MultipartFormDataContent 相关内容的代码。这些地方从 .NET Framework 迁移到 .NET Core 之后的代码改动较大,由于本身没有测试覆盖,导致在部署 QA 环境后引发了一些问题。这里做一个技术复盘。 什么是 MultipartFormDataCon…

    C# 2023年4月19日
    00
  • Netcore Webapi返回数据的三种方式示例

    下面我来介绍一下“Netcore Webapi返回数据的三种方式示例”的完整攻略。 概述 在开发Webapi时经常需要返回各种数据,例如字符串、Json格式数据、XML格式数据、二进制文件、图片等等。本篇文章将介绍Netcore Webapi返回数据的三种方式示例,分别为返回字符串、返回Json格式数据和返回文件。 返回字符串 在Webapi中,返回字符串最…

    C# 2023年6月3日
    00
  • unity实现按住鼠标选取区域截图

    实现按住鼠标选取区域截图,可以分为以下几个步骤: 步骤1:创建一个可以截图的摄像机 在场景中创建一个新的摄像机,并将其与原本的主摄像机分离。可以使用Screen Capture With UI插件或直接编写脚本进行实现。 using System.Collections; using System.Collections.Generic; using Uni…

    C# 2023年6月3日
    00
  • Entity Framework使用Code First模式管理事务

    使用Entity Framework的Code First模式管理事务可以帮助开发人员更加便捷地创建数据库和管理事务,下面是使用Code First模式管理事务的详细攻略。 1. 定义实体类 首先,需要定义要映射到数据库的实体类。可以使用标准的C#类来定义实体类,但需要使用特定的约定来指定表名、主键等属性,如下面的示例所示: public class Cus…

    C# 2023年6月3日
    00
  • 详解C# winform ListView的基本操作

    详解C# WinForm ListView的基本操作攻略 介绍 C# WinForm中的ListView是一种非常常用的用于显示数据的控件,本攻略将详细讲解如何使用C# WinForm ListView实现基本操作,包括: ListView的基本属性设置 列表视图、图标视图、详情视图和小图标视图的展示方式 添加、删除和编辑ListView的项 ListVie…

    C# 2023年6月1日
    00
合作推广
合作推广
分享本页
返回顶部