使用BackgroundWorker使用网格

时间:2010-09-23 09:16:47

标签: c# .net backgroundworker devexpress xtragrid

我使用GridControl填充BackgroundWorker。然后我使用另一个BackgroundWorker对数据集执行一些计算,数据集是GridControl的数据源。在我尝试这样做时,会抛出GridControl错误的交叉线程操作。我无法理解尽管没有对gridcontrol本身的任何操作执行错误的产生。 (我正在使用DevExpress,但这不应该改变这个概念。)

还有什么方法可以使用BackgroundWorker来完成不同的工作,即使这段代码更有效率。

这是我的代码: -

public partial class MainForm : XtraForm
    {
        private BackgroundWorker loadworker = new BackgroundWorker();
        private BackgroundWorker calcworker = new BackgroundWorker();
        private AutoResetEvent resetEvent = new AutoResetEvent(false);
        private Database _db = EnterpriseLibraryContainer.Current.GetInstance<Database>("ConnString");
        private DataSet ds;

        public MainForm()
        {
            InitializeComponent();

            loadworker.DoWork += loadworker_DoWork;
            loadworker.RunWorkerCompleted += loadworker_RunWorkerCompleted;
            loadworker.ProgressChanged += loadworker_ProgressChanged;
            loadworker.WorkerReportsProgress = true;

            calcworker.DoWork += calcworker_DoWork;
            calcworker.RunWorkerCompleted += calcworker_RunWorkerCompleted;
            calcworker.ProgressChanged += calcworker_ProgressChanged;
            calcworker.WorkerReportsProgress = true;
        }

        private void calcworker_DoWork(object sender, DoWorkEventArgs e)
        {
            int _cnt = 0;
            foreach (DataRow dr in ds.Tables[0].Rows)
            {
                dr["GROSS"] = (decimal)dr["BASIC"] + (decimal)dr["HRA"] + (decimal)dr["DA"];
                _cnt += 1;
            }

            for (int i = 0; i <= _cnt; i++)
            {
                Thread.Sleep(100);
                calcworker.ReportProgress((100 * i) / _cnt);
            }
        }

        private void calcworker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            this.SetState(true);
            this.MainInit();
        }

        private void calcworker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            this.pgb_DataProgress.Position = e.ProgressPercentage;
        }


        private void loadworker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            this.pgb_DataProgress.Position = e.ProgressPercentage;
        }

        private void loadworker_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                DbCommand _cmd = _db.GetSqlStringCommand("SELECT Z.EMP_CODE,Z.BASIC,Z.DA,Z.HRA,CAST(0 AS DECIMAL) GROSS FROM Z000000001 Z");
                DataSet _data = _db.ExecuteDataSet(_cmd);

                for (int i = 0; i <= 10; i++)
                {
                    Thread.Sleep(500);
                    loadworker.ReportProgress((100 * i) / 10);
                }

                e.Result = _data;
            }
            catch (Exception ex)
            {
                e.Cancel = true;
            }
        }

        private void loadworker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            this.ds = (DataSet)e.Result;
            this.gridControl1.DataSource = ds.Tables[0];
            this.SetState(true);
            this.MainInit();
        }

        private void btn_FetchData_Click(object sender, EventArgs e)
        {
            this.gridControl1.DataSource = null;
            this.SetState(false);
            loadworker.RunWorkerAsync();
        }

        private void SetState(bool _state)
        {
            this.btn_Calculate.Enabled = _state;
            this.btn_ClearGrid.Enabled = _state;
            this.btn_FetchData.Enabled = _state;
        }

        private void MainInit()
        {
            this.pgb_DataProgress.Position = 0;
        }

        private void btn_ClearGrid_Click(object sender, EventArgs e)
        {
            this.gridControl1.DataSource = null;
        }

        private void btn_Calculate_Click(object sender, EventArgs e)
        {
            if (this.gridControl1.DataSource == null)
            {
                DevExpress.XtraEditors.XtraMessageBox.Show("Data Not loaded", "Message");
                return;
            }
            else
            {
                this.SetState(false);
                calcworker.RunWorkerAsync();
            }
        }

    }

2 个答案:

答案 0 :(得分:1)

将表作为DataSource附加后,它属于GUI。假设您的用户在Calc线程运行时更改/删除一行。各种各样的竞争条件都可能发生。

答案 1 :(得分:0)

简而言之,您无法访问创建它们的UI线程以外的线程上的控件。因此,任何控制方法/属性调用都必须使用Control.Invoke方法在UI线程上进行编组。

例如,在您的情况下,将在工作线程上调用loadworker_RunWorkerCompleted事件处理程序,并且访问控件属性将引发错误。您需要将事件处理程序修改为

    private void loadworker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        System.Action a = () => {
          this.ds = (DataSet)e.Result;
          this.gridControl1.DataSource = ds.Tables[0];
          this.SetState(true);
          this.MainInit();
        };
        this.gridControl1.Invoke(a);
    }