WinForm中异步加载数据并使用进度条

在WinForm程序中,有时会因为加载大量数据导致UI界面假死,这种情况对于用户来说是非常不友好的。因此,在加载大量数据的情况下,首先应该将数据加载放在另一线程中进行,这样保证了UI界面的响应;其次可以提供一个进度条使用户明白程序正在加载数据,同时清楚知道目前加载的进度。

实现上述功能的一个简单的方式是利用 System.ComponentModel 中的工具类:BackgroundWorker,它支持取消,进度报告,异常转发,并且实现了 IComponent 接口,意味着可以直接在VS设计器中从工具箱中拖到界面上使用。

下面以一个例子来说明如何使用 BackgroundWorker,更详细的 BackgroundWorker 说明可以参考Threading in C#(或者 中文翻译):

1. UI界面添加一个进度条,一个开始按钮,一个结束按钮,以及BackgroundWorker,并设置下列 BackgroundWorker 属性(例子中设置了其Name为bw):

  • WorkerReportsProcess:默认为False,将其设置为True,支持进度报告
  • WorkerSupportsCancellation:默认为False,将其设置为True,支持取消

2. DoWork事件,在其中执行我们的数据加载,我们执行一个循环来模拟数据加载

private void bw_DoWork(object sender, DoWorkEventArgs e)
{
    var count = (int)e.Argument;
    for (int i = 1; i <= count; i++)
    {
        if (bw.CancellationPending)
        {
            e.Cancel = true;
            return;
        }

        bw.ReportProgress(i);
        Thread.Sleep(200);      // 模拟耗时的任务
    }
}
  • 注意:在这个方法中不能进行UI控件的更新。
  • 通过检查 CancellationPending 来判断用户是否进行了取消
  • 通过调用 ReportProgress 来报告进度

3. ProgressChanged 事件,在这里可以操作进度条,以及其他UI控件。

private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    progressBar.Value = e.ProgressPercentage;
    resultTextBox.Text += DateTime.Now + "\r\n";
}

通过e.ProgressPercentage来获取任务执行过程中设置的进度,以此来更新进度条。

4. RunWorkerCompleted 事件,在这里可以更新UI,以及进行异常处理。

private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Cancelled)
        resultTextBox.Text += "任务取消。" + "\r\n";
    else if (e.Error != null)
        resultTextBox.Text += "出现异常: " + e.Error + "\r\n";
    else
        resultTextBox.Text += "任务完成。 " + "\r\n";
}

当执行过程中出现异常时,异常会被转发到这里,因此可以在这里处理异常。

5. 通过一个开始按钮调和一个取消按钮来控制:

  • bw.RunWorkerAsync()   启动
  • bw.CancelAsync()  取消

下边是完整的代码及输出:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        bw.DoWork += bw_DoWork;
        bw.ProgressChanged += bw_ProgressChanged;
        bw.RunWorkerCompleted += bw_RunWorkerCompleted;
    }

    private void startButton_Click(object sender, EventArgs e)
    {
        progressBar.Value = 0;
        progressBar.Maximum = 10;

        resultTextBox.Text = "任务开始..." + "\r\n";
        bw.RunWorkerAsync(10);
    }

    private void bw_DoWork(object sender, DoWorkEventArgs e)
    {
        var count = (int)e.Argument;
        for (int i = 1; i <= count; i++)
        {
            if (bw.CancellationPending)
            {
                e.Cancel = true;
                return;
            }

            if (i == 2)
                throw new Exception("出错啦!");

            bw.ReportProgress(i);
            Thread.Sleep(200);
        }
    }

    private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Cancelled)
            resultTextBox.Text += "任务取消。" + "\r\n";
        else if (e.Error != null)
            resultTextBox.Text += "出现异常: " + e.Error + "\r\n";
        else
            resultTextBox.Text += "任务完成。 " + "\r\n";
    }

    private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressBar.Value = e.ProgressPercentage;
        resultTextBox.Text += DateTime.Now + "\r\n";
    }

    private void cancelbutton_Click(object sender, EventArgs e)
    {
        bw.CancelAsync();
    }
}

输出如下:

参考:Threading in C# --> 中文翻译

时间: 2025-01-05 03:57:27

WinForm中异步加载数据并使用进度条的相关文章

iOS中异步加载数据效率更高

在开发中有得时候虽然也能从服务器返回来数据,但是我们要根据实际情况,加快数据的显示,所以我们使用异步加载数据. 下面我们看一下如何异步加载数据 dispatch_async(dispatch_get_global_queue(0, 0), ^{ //下载数据(这里写的是使用AFNetWorking请求的数据) dispatch_async(dispatch_get_main_queue(), ^{ //更新视图(这里写的是,要把数据显示出来) }); });

学习andriod开发之 异步加载图片--- 使用系统进度条

大家好 我是akira 学习图片异步加载的例子 说道这里有人可能要问了 什么是异步 为什么要用异步 why? 说白了很简单 省时间 省资源 我举个例子你就懂了 比如你在下东西 至于下什么 那些邪恶的骚年们又要YY了 不去管他们.比如你在下东西 这个时候 另外一个人也在下同一个东西 那么那个人怎么办 他就等你下完 等到天荒地老?ありえないこと impossible 他肯定也要下 那么问题就来了 他如何下?这个时候就要用到异步 说道这里 有人可能问什么叫同步 什么叫异步 我在这里在给大家举一个简单的

异步加载场景及Loading进度条制作

实现功能:点击开始游戏以后UI界面进入Loading界面,Loading结束以后自动进入游戏场景. 在这之前先在Build Settings中Add要使用的场景 在场景A中添加StartGame方法: Application.LoadLevel(1)://同步加载Loading界面(因为Loading界面资源较少速度快所以此处用同步方法) 在Loading场景中加入进度条图片:分为上下两层,上层负责显示进度 将上层的进度条Image组件中的Image Ttpe改为Filled 接下来再Loadi

异步加载场景和Loading进度条制作

在切换场景的时候,直接 用 application.LoadLevel()这个方法,如果加载的场景资源过多的话,会卡死一段时间的. 所以,用一个过渡的场景的话,体验会好一点. 那么就先开始做一个过渡的场景(名字叫做:Loading)吧..(比如像下面酱紫,百度的一张图片) 要切换场景的时候,Application.LoadLevel("Loading"):就先切换到这个Loading场景,Loading场景资源少,就一个背景图和一个slider,所以,直接同步加载过来也很快的 然后,在

winform异步加载数据到界面

做一个学习记录. 有两个需求: 1.点击按钮,异步加载数据,不卡顿UI. 2.把获取的数据加载到gridview上面. 对于需求1,2,代码如下: public delegate void ShowDatatableDelegate(DataTable dt); private async void button1_Click(object sender, EventArgs e) { //way1.ok Thread t = new Thread(ShowDatatable); t.IsBac

SpringMVC+Jquery -页面异步加载数据

背景: 做项目时涉及到页面,当我打算在controller中传一个list到页面,然后通过<c:foreach>循环遍历出来时,同事说:你这样每次都要刷新,这都是几百年前使用的技术了.你用post实现异步加载数据.然后就...... ResultUtil.java 工具类: package com.sgcc.uds.fs.config.web.util; import java.util.HashMap; import java.util.Map; import net.sf.json.JSO

jQuery异步加载数据添加事件

几个月前在一个项目中涉及到树形栏,然后看了很多插件,觉得有点麻烦,于是自己写了一个,写着写着就出问题了.当时项目是通过树形栏进行权限控制的,管理员可以对从数据库去的数据动态生成树形栏进行增删改查操作,可是用$(".XX").click();方法是不行的.1.之前用的是jq1.4.3 ,jq1.7一下都可以使用live()方法,来实现该功能 $('#div').live('click',function(){ //do stuff }); 但是live方法也有不支持的事件,例如:togg

Android利用Volley异步加载数据完整详细示例(二)

MainActivity如下: package cc.y; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.os.Bundle; import android.util.LruCache; import android.widget.ImageView;

Android利用Volley异步加载数据完整详细示例(一)

MainActivity如下: package cc.cn; import java.util.HashMap; import org.json.JSONObject; import android.app.Activity; import android.content.Context; import android.os.Bundle; import com.android.volley.AuthFailureError; import com.android.volley.RequestQ