简体   繁体   English

使用BackgroundWorker刷新Winforms C#中的数据网格

[英]Using BackgroundWorker to refresh datagrid in winforms C#

I'm having an issue with a form that uses a background worker thread to fetch data and update a datagrid. 我在使用后台工作程序线程来获取数据和更新数据网格的表单时遇到问题。

The use case is a list with progress bars that shows how much tables have loaded in a database. 用例是带有进度条的列表,该进度条显示了数据库中已装入多少表。

It goes in the following order, 它按以下顺序进行,

  • FormA instantiates FormB FormA实例化FormB
  • FormB kicks of a background worker that loops to fetch data and update a datagrid.datasource. 后台工作程序的FormB脚踢,该工作程序循环获取数据并更新datagrid.datasource。

It works nicely sometimes but others the FormB.ShowDialog() comes back with a null reference exception. 有时它可以很好地工作,但是其他FormB.ShowDialog()会返回带有空引用异常。 I can't understand why. 我不明白为什么。

Here's the calling form code: 这是呼叫表单代码:

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

    }

The child form (It's the second backgroundworker that does the datagrid update): 子窗体(这是第二个进行datagrid更新的背景工作人员):

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

    }

You should use the BackgroundWorker.ReportProgress Method (Int32, Object) as shown in the documentation here . 您应该使用BackgroundWorker.ReportProgress Method (Int32, Object)如图所示文档这里 I always use the second parameter to pass an enum to identify from which background worker was this progress reported. 我始终使用第二个参数传递一个enum以标识从哪个后台工作人员报告了此进度。 You can use a similar approach. 您可以使用类似的方法。

So I found a solution that works nicely. 所以我找到了一个很好的解决方案。 Basically I changed the background worker to a task that gets the data and then invokes the dataGridView that needed updating. 基本上,我将后台工作程序更改为获取数据的任务,然后调用需要更新的dataGridView。 Eg 例如

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

Renamed the background worker to UpdateUI and inside: 将后台工作人员重命名为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(); }));
                    }
                }

            }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM