C# 在WinC窗体中使用BackgroundWorker刷新数据网格#
我遇到了一个表单问题,它使用后台工作线程获取数据并更新数据网格 用例是一个带有进度条的列表,显示数据库中加载了多少表 它的顺序如下:C# 在WinC窗体中使用BackgroundWorker刷新数据网格#,c#,multithreading,winforms,backgroundworker,C#,Multithreading,Winforms,Backgroundworker,我遇到了一个表单问题,它使用后台工作线程获取数据并更新数据网格 用例是一个带有进度条的列表,显示数据库中加载了多少表 它的顺序如下: FormA实例化FormB FormB是一个后台工作程序的循环,用于获取数据和 更新datagrid.datasource 它有时工作得很好,但另一些FormB.ShowDialog()返回时出现空引用异常。我不明白为什么 以下是呼叫表单代码: private void button1_Click(object sender, EventArgs e)
- 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;
}
}
}
子表单(它是执行datagrid更新的第二个backgroundworker):
您应该使用
BackgroundWorker.ReportProgress方法(Int32, 对象)
如文档所示。我总是使用第二个参数传递一个enum
,以确定报告此进度的后台工作人员。您可以使用类似的方法。因此我找到了一个很好的解决方案。基本上,我将后台工作程序更改为获取数据的任务,然后调用需要更新的dataGridView。例如
Task.Factory.StartNew(() =>
UpdateUI());
将后台工作程序重命名为UpdateUI和inside:
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(); }));
}
}
}
为什么要使用后台工作程序而不是像async/await这样的现代方法?@rory.ap我碰巧选择了这个作为解决方案。如果有更好的方法,我很乐意改变它。就像我说的,当这个奇怪的错误没有发生时,它工作得很好。不要直接从后台工作线程更新UI:使用
Invoke
或backgroundWorker.ReportProgress()
等CheckForIllegalCrossThreadCalls=false
是一个非常糟糕的主意!对于例外情况:准确地检查堆栈跟踪,f
不能为空,或者请参见:在盲目地跳入多线程编程之前,您需要了解多线程编程和可用的方法。委婉地说,这是一个高级主题,如果你不了解自己在做什么,你将面临无休止的问题和不满意的客户。@EvanBarke在任何操作系统中,你都不能从另一个线程修改UI。这意味着您不能从DoWork
修改网格。您必须处理RunWorkerCompleted
事件并修改那里的UI。此时使用async/await
要容易得多。将两个异步操作与BGW结合起来要困难得多,但这并没有帮助。ReportProgress报告一个百分比值。我需要替换DataGridView1的整个数据源。您可以将datatable作为第二个参数传递,实际上不需要关心百分比。
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(); }));
}
}
}