Использование BackgroundWorker для обновления сетки данных в winforms C # - PullRequest
0 голосов
/ 18 мая 2018

У меня проблема с формой, которая использует фоновый рабочий поток для извлечения данных и обновления сетки данных.

Вариант использования - это список с индикаторами выполнения, которые показывают, сколько таблиц загружено вбаза данных.

Идет в следующем порядке,

  • FormA создает FormB
  • Удары FormB фонового работника, который зацикливается для выборки данных и обновления источника данных datagrid.datasource.

Иногда это работает хорошо, но в других случаях FormB.ShowDialog() возвращается с нулевым ссылочным исключением.Я не могу понять, почему.

Вот код формы вызова:

 private void button1_Click(object sender, EventArgs e)
    {


        using (var f = new FormFactProgress(_dwConnectionString, _sourceConnectionString, _etlConnectionString))
        {
            f.ShowDialog();  \\ THIS IS WHERE THE NULL REFERENCE EXCEPTION ALWAYS HAPPENS!
            labelLoadWarning.Visible = false;
            groupBoxLoadFacts.Enabled = false;
            buttonLoadFacts.BackColor = Color.FromArgb(128, 255, 128);
            buttonLoadFacts.Text = "Loaded";
            if (dynamicWarehouseCatalog.FactsLoaded(_dwConnectionString) && dynamicWarehouseCatalog.DimsLoaded(_dwConnectionString))
            {
                groupBoxSync.Enabled = true;
            }
        }

    }

Дочерняя форма (это второй фоновый работник, который обновляет сетку данных):

private void buttonStart_Click(object sender, EventArgs e)
    {
        backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
        if (!backgroundWorker1.IsBusy)
        {
            backgroundWorker1.RunWorkerAsync();
        }
        backgroundWorker2.DoWork += new DoWorkEventHandler(backgroundWorker2_DoWork);
        if (!backgroundWorker2.IsBusy)
        {
            backgroundWorker2.RunWorkerAsync();
        }
        buttonStart.Enabled = false;


    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        try
        {
            BackgroundWorker worker = (BackgroundWorker)sender;

            sSISDBCatalog.StartFactLoad(_etlConnectionString);

            while (isLoading)
            {
                System.Threading.Thread.Sleep(1000);
                if (dynamicWarehouseCatalog.FactsLoaded(_dwConnectionString))
                {
                    if (dynamicWarehouseCatalog.AllFactsLoaded(_dwConnectionString))
                    {
                        isLoading = false;
                    }
                }
            }
        }
        catch(Exception ex)
        {
            MessageBox.Show(
           "Progress viewing has failed. The ETL is still running though. Please monitor your data warehouse growth manually. Error: " + ex, "Pregress Visualisation Failed",
           MessageBoxButtons.OK,
           MessageBoxIcon.Error);
            return;
        }


    }

    private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
    {
        try
        {
            Control.CheckForIllegalCrossThreadCalls = false;
            BackgroundWorker worker = (BackgroundWorker)sender;
            var dw = DwData(_dwConnectionString);
            var source = SourceData(_sourceConnectionString);
            dataGridView1.DataSource = GetProgress(dw, source);
            while (isLoading)
            {
                System.Threading.Thread.Sleep(1000);
                dw = DwData(_dwConnectionString);
                dataGridView1.DataSource = GetProgress(dw, source);
                dataGridView1.Refresh();
            }

            MessageBox.Show(
               "Your data warehouse facts are loaded!", "Facts Loaded",
               MessageBoxButtons.OK,
               MessageBoxIcon.Information);
            return;
        }
        catch (Exception ex)
        {
            MessageBox.Show(
           "Progress viewing has failed. The ETL is still running though. Please monitor your data warehouse growth manually. Error: " + ex, "Pregress Visualisation Failed",
           MessageBoxButtons.OK,
           MessageBoxIcon.Error);
            return;
        }

    }

Ответы [ 2 ]

0 голосов
/ 21 мая 2018

Итак, я нашел решение, которое прекрасно работает.В основном я изменил фонового работника на задачу, которая получает данные, а затем вызывает dataGridView, который необходимо обновить.Например,

Task.Factory.StartNew(() =>
                    UpdateUI()); 

Переименован фоновый рабочий в UpdateUI и внутри:

var dw = DwData(_dwConnectionString);
            var source = SourceData(_sourceConnectionString);
            DataTable prog;
            while (isLoading)
            {
                System.Threading.Thread.Sleep(1000);
                dw = DwData(_dwConnectionString);
                if (dw.Rows.Count > 0)
                {                     
                    prog = GetProgress(dw, source);
                    if (prog.Rows.Count > 0)
                    {
                        dataGridView1.Invoke(new MethodInvoker(() => { dataGridView1.DataSource = prog; dataGridView1.Refresh(); }));
                    }
                }

            }
0 голосов
/ 18 мая 2018

Вы должны использовать BackgroundWorker.ReportProgress Method (Int32, Object), как показано в документации здесь .Я всегда использую второй параметр, чтобы передать enum, чтобы определить, от какого фонового работника был получен этот прогресс.Вы можете использовать аналогичный подход.

...