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日

相关文章

  • ASP.NET Core 6最小API中使用日志和DI示例详解

    ASP.NET Core 6最小API中使用日志和DI示例详解 在ASP.NET Core 6中,最小API是一种轻量级的方式来构建Web API。在本攻略中,我们将介绍如何在ASP.NET Core 6最小API中使用日志和DI。以下是ASP.NET Core 6最小API中使用日志和DI示例详解的完整攻略: 步骤一:创建最小API 首先,需要创建一个最小…

    C# 2023年5月17日
    00
  • .Net Core日志记录之日志配置

    .Net Core日志记录之日志配置 在 .Net Core 中进行日志记录,可以帮助我们更好地了解应用程序运行时的情况,以及修复可能出现的问题。本文介绍如何在 .Net Core 应用程序中配置日志记录。 1. 新建 .Net Core Web 应用程序 首先,我们需要创建一个基本的 .Net Core Web 应用程序。可以使用 Visual Studi…

    C# 2023年6月3日
    00
  • ASP.NET Core – 缓存之内存缓存(下)

    话接上篇 [ASP.NET Core – 缓存之内存缓存(上)],所以这里的目录从 2.4 开始。 2.4 MemoryCacheEntryOptions MemoryCacheEntryOptions 是内存缓存配置类,可以通过它配置缓存相关的策略。除了上面讲到的过期时间,我们还能够设置下面这些: 设置缓存优先级。 设置在从缓存中逐出条目后调用的 Post…

    C# 2023年4月17日
    00
  • .NET Core开源 DDD微服务 支持 多租户 单点登录 多级缓存、自动任务、分布式、日志、授权和鉴权 、网关 、注册与发现 系统架构 docker部署

    源代码地址https://github.com/junkai-li/NetCoreKevin基于NET6搭建跨平台DDD思想WebApi架构、IDS4单点登录、多缓存、自动任务、分布式、多租户、日志、授权和鉴权、CAP、SignalR、 docker部署  如需简约项目可直接去除项目引用 解耦设计都可以单独引用 架构默认全部引用并启动 项目启动时注意相关 R…

    C# 2023年4月24日
    00
  • 如何在ASP.NET Core类库项目中读取配置文件详解

    如何在ASP.NET Core类库项目中读取配置文件详解 在ASP.NET Core中,读取配置文件是非常常见的操作。本攻略将提供详细的步骤和示例说明,演示如何在ASP.NET Core类库项目中读取配置文件。 步骤 步骤1:创建一个新的ASP.NET Core类库项目 首先,需要创建一个新的ASP.NET Core类库项目。可以使用以下命令在命令行中创建一…

    C# 2023年5月17日
    00
  • Entity Framework主从表数据加载方式

    Entity Framework(EF)是一种ORM(对象关系映射)框架,是将面向对象编程与关系型数据库结合起来的工具。在许多场景下,我们需要加载主从表间的数据,而Entity Framework提供了几种不同的方式来实现这个目标。 1.贪婪加载( Eager Loading) 贪婪加载是指在加载父对象时,同时将所有相关的子对象一起加载。例如下面这个示例: …

    C# 2023年6月3日
    00
  • 用C#来解析PDF文件

    当我们要使用 C# 来解析 PDF 文件时,可以使用一些开源库,例如 iTextSharp、PDFSharp 和 Syncfusion.PDF 等。这些库可以帮助我们进行 PDF 文档的读取和编辑,并且提供了一些 API 用于实现文档的操作。 接下来,我们来具体讲解使用 iTextSharp 库和 PDFSharp 库来解析 PDF 文件的两个示例: 示例1…

    C# 2023年5月15日
    00
  • 基于Silverlight DataGrid中无代码设置开始与结束日期DatePicker的实现方法

    下面给你详细讲解一下基于Silverlight DataGrid中无代码设置开始与结束日期DatePicker的实现方法的完整攻略。 问题概述 在Silverlight应用程序中使用DataGrid控件时,常常需要使用DatePicker控件来设置开始和结束日期筛选条件,但是如何无代码来实现这个功能呢? 解决方案 在Silverlight DataGrid控…

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