异步的后台工作者等待任务

时间:2016-07-27 18:04:32

标签: c# async-await devexpress backgroundworker

下面是示例代码,它使用devexpress bareditItem(progressbar)来显示加载数据时的进度。我想知道是否有一种方法可以使用异步等待和任务显示相同的进度条(显示数据加载时的进度)。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace ProgressBar {
    public partial class Form1 : DevExpress.XtraEditors.XtraForm {

        DataTable workTable;

        public Form1() {
            InitializeComponent();
            workTable = new DataTable("Records");
            workTable.Columns.Add("Id", typeof(int));
            workTable.Columns.Add("Data", typeof(String));
        }

        //this data varies from 0 to 50,000 rows
        private void LoadData(DoWorkEventArgs e) {
            for(int i = 0; i < 1001; i++) {
                System.Threading.Thread.Sleep(5);
                workTable.Rows.Add(i, String.Format("Record {0}", i));
                this.backgroundWorker1.ReportProgress(i, i);
            }

        }

        private void button1_Click(object sender, EventArgs e) {
            this.backgroundWorker1.RunWorkerAsync();
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {
            LoadData(e);
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) {
            DataTable up = workTable.Clone();
            this.barEditItem1.EditValue = e.ProgressPercentage;
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
            gridControl1.DataSource = workTable;
        }
    }
}

3 个答案:

答案 0 :(得分:1)

您的代码可以使用async/await模式和Progress<T>类进行转换和简化,以确保在正确的线程上进行进度报告更新:

namespace ProgressBar {
    public partial class Form1 : DevExpress.XtraEditors.XtraForm {

        DataTable workTable;

        public Form1() {
            InitializeComponent();
            workTable = new DataTable("Records");
            workTable.Columns.Add("Id", typeof(int));
            workTable.Columns.Add("Data", typeof(String));
        }

        //this data varies from 0 to 50,000 rows
        private void LoadData(IProgress<int> progress) {
            for(int i = 0; i < 1001; i++) {
                System.Threading.Thread.Sleep(5);
                workTable.Rows.Add(i, String.Format("Record {0}", i));
                progress.Report(i);
            }
        }

        private async void button1_Click(object sender, EventArgs e) {
            // 1. This replaces: backgroundWorker1_ProgressChanged
            var progress = new Progress<int>(
              i => 
              {
                // This code will execute on the UI thread, as it should
                DataTable up = workTable.Clone();
                this.barEditItem1.EditValue = i;
              });

            // 2. This replaces: backgroundWorker1_DoWork
            await Task.Run(() => this.LoadData(progress));

            // 3. This replaces: backgroundWorker1_RunWorkerCompleted
            gridControl1.DataSource = workTable;
        }
    }
}

我留下了几行代码,我认为你实际上并不需要,例如Thread.SleepDataTable up = workTable.Clone();,但我确定你可以想出来。

答案 1 :(得分:0)

BackgroundWorker对我来说是一个过时的功能(自async-await功能发布以来)。从现在开始尝试不要使用它。这相当于使用花式async-await:

private async void button1_Click(object sender, EventArgs e)
{
    await LoadData();
}

private async Task LoadData()
{
    for (int i = 0; i < 1001; i++)
    {
        await Task.Delay(5);
        workTable.Rows.Add(i, String.Format("Record {0}", i));

        DataTable up = workTable.Clone(); // useless but copied from your code
        this.barEditItem1.EditValue = i;
    }
    gridControl1.DataSource = workTable;
}

答案 2 :(得分:-1)

当然有。不要使用后台工作人员,因为它已经过时了。

这里有一些(未经测试的)代码可以帮助您上路。 SynchronizationContext可防止跨线程异常。可能有更好的方法可以做到这一点,但这就是我的用法。

namespace ProgressBar
{
    using System.ComponentModel;
    using System.Data;
    using System.Threading;
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;

    public partial class Form1 : DevExpress.XtraEditors.XtraForm
    {

        private DataTable workTable;
        private SynchronizationContext _context;

        public Form1()
        {
            InitializeComponent();

            this._context = SynchronizationContext.Current;

            workTable = new DataTable("Records");
            workTable.Columns.Add("Id", typeof(int));
            workTable.Columns.Add("Data", typeof(String));
        }

        private async Task LoadData()
        {
            const int iterations = 1001; //whatever you want...

            for (int i = 0; i < iterations; i++)
            {
                workTable.Rows.Add(i, String.Format("Record {0}", i));
                this._context.Post(() =>
                {
                    this.UpdateWorkProgress((int) i /iterations)
                });
            }
        }

        private void UpdateWorkProgress(int percent)
        {
            this.barEditItem1.EditValue = percent;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            await this.LoadData();
            gridControl1.DataSource = workTable;
        }        
    }
}