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#简单生成随机密码的方法示例”的完整攻略。 1. 生成随机密码 生成随机密码的方法比较多,可以通过随机函数生成随机字符序列,也可以从字符集中随机选取字符生成密码。下面我将介绍几种方法。 1.1 使用 Random 类 可以使用 Random 类生成随机数,然后将生成的随机数转为希望的字符序列(如数字、字母和特殊字符),从而组成随机密码…

    C# 2023年6月7日
    00
  • C# 创建、部署和调用WebService简单示例

    下面我会详细讲解“C# 创建、部署和调用WebService简单示例”的完整攻略。 什么是Web Service? Web Service即 Web 服务,它是一种跨平台、跨编程语言实现的远程调用技术。通过Web Service,我们可以让不同的系统之间互相通信和交互。在Web Service中,数据以XML格式传输,使用简单易懂的HTTP协议通信。 如何创…

    C# 2023年6月3日
    00
  • C#中的var关键字用法介绍

    C#中的var关键字用法介绍 一、var关键字的作用 C#中的var关键字允许我们在编译时推断出变量的类型,并在必要时进行转换。使用var关键字可以大大简化代码,提高可读性和编程效率。 二、var关键字的使用方法 1. 声明变量时使用var关键字 var关键字可以用来声明各种类型的变量,包括整型、浮点型、字符串型、数组等。 示例1:声明一个整型变量 var …

    C# 2023年5月15日
    00
  • asp.net 文章分页显示实现代码

    下面是关于实现asp.net文章分页显示的攻略和示例: 1. 确定分页参数 文章分页需要确定几个重要的参数: 每页显示的文章数量 当前页码 文章总数 总页数 可以根据以上参数进行分页计算,具体代码可以参考下面的示例。 2. 实现后端分页方法 接下来需要在代码中实现后端分页方法,下面是一个简单的示例: // 分页方法 public List<Articl…

    C# 2023年5月31日
    00
  • C#从DataTable获取数据的方法

    下面我们来详细讲解一下“C#从DataTable中获取数据的方法”的完整攻略,包括以下几个内容: DataTable 简介 从 DataTable 中获取数据的方法 代码示例说明 1. DataTable 简介 DataTable 是 System.Data 命名空间中的一个类,代表一个内存中的数据表格,其中包含了行和列等各种数据信息,可用于存储和处理数据。…

    C# 2023年5月31日
    00
  • C#对JSON与对象的序列化与反序列化

    下面是详细讲解”C#对JSON与对象的序列化与反序列化”的完整攻略。 什么是序列化和反序列化 序列化是将对象的状态转换为可存储或传输的形式的过程,通常将对象转换为二进制流或文本格式(如JSON或XML)。反序列化是将序列化后的数据重新转换回对象的过程。 在C#中,可以使用序列化将对象转换为JSON格式,以便在网络上传输或存储数据。 C#中的JSON序列化和反…

    C# 2023年6月3日
    00
  • efcore性能调优

    性能调优——EFCore调优 按下硬件、网络不提,我们单表从程序层面对系统的性能进行优化,翻来覆去无外乎三个方面 缓存 异步 sql本片文章,我们针对.net core web项目的ef core框架进行性能优化。 1. EF Core框架已经本地缓存机制memorycache,所以我们访问一个接口,二次访问的性能相比首次会提升一大截 2.尽可能的通过主键查…

    C# 2023年5月5日
    00
  • asp.net获取当前网址url的各种属性(文件名、参数、域名 等)的代码

    当ASP.NET页面和控件运行时,可以通过Request对象的属性来获取当前网址的各种属性。 以下是获取当前网址url的一些常用属性: 获取当前页面的URL Request.Url.AbsoluteUri 该属性返回当前页面的完整URL,包括协议、域名、端口号、路径和查询字符串。如:https://www.example.com/test.aspx?id=1…

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