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


    在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 + "
    ";
    }

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

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

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

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

    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 = "任务开始..." + "
    ";
            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 += "任务取消。" + "
    ";
            else if (e.Error != null)
                resultTextBox.Text += "出现异常: " + e.Error + "
    ";
            else
                resultTextBox.Text += "任务完成。 " + "
    ";
        }
    
        private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar.Value = e.ProgressPercentage;
            resultTextBox.Text += DateTime.Now + "
    ";
        }
    
        private void cancelbutton_Click(object sender, EventArgs e)
        {
            bw.CancelAsync();
        }
    }
    复制代码

    输出如下:

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

    出处:http://www.cnblogs.com/samgk/p/4774977.html

  • 相关阅读:
    PHP-FPM doesn't write to error log
    CSS中position属性( absolute | relative | static | fixed )详解
    微信分享踩坑
    使用layer-list实现特殊的效果
    如何正确的给ViewGroup设置OnClickListener
    android:clipchildren属性
    学习有边界吗?学了几年感觉什么也做不出,学习无用?
    电动车的蓄电池与锂电池
    《增长黑客》节选与笔记
    Firefox火狐浏览器的高效使用
  • 原文地址:https://www.cnblogs.com/mq0036/p/10762349.html
Copyright © 2020-2023  润新知