Работа с сеткой с использованием BackgroundWorker - PullRequest
0 голосов
/ 23 сентября 2010

У меня есть 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 ]

1 голос
/ 23 сентября 2010

После того, как вы прикрепили таблицу в качестве источника данных, она принадлежит графическому интерфейсу.Предположим, ваш пользователь изменяет / удаляет строку во время работы потока Calc.Могут возникнуть всевозможные условия гонки.

0 голосов
/ 23 сентября 2010

Короче говоря, вы не можете получить доступ к элементам управления в потоке, отличном от потока пользовательского интерфейса, в котором они созданы. Поэтому любой вызов метода / свойства элемента управления должен выполняться в потоке пользовательского интерфейса с использованием метода Control.Invoke .

Например, в вашем случае обработчик события loadworker_RunWorkerCompleted будет вызван в рабочем потоке, а доступ к свойству control вызовет ошибку. Вам нужно изменить обработчик событий как

    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);
    }
...