C# datagrid迭代更新期间弹出状态窗口
我花了4个小时在这上面,但完全失败了。 我知道我需要使用BackgroundWorker,但所有教程都提到在运行worker的实际表单上运行进度脚本 我有一个大型datagrid,用户可以使用复选框选择all,然后按UPDATE all 这将使用他们选择的一系列选项更新每个网格。 对于某些用户来说,这可能是5条记录,这算不了什么,但有些用户可能会使用5个选项更新200条记录,这需要大约。。。10-15秒的时间来迭代 我已经尝试了很多运行BGworker的变体,它加载一个FrmLoading.Showdialog 或者尝试让BGworker运行代码,然后让主线程运行FrmLoading.Show 然而,一切都不起作用 如果我在后台工作程序中有更新代码,它会失败,因为datagrid和所有内容都在不同的线程中 另一方面,它只是挂在FRM加载。显示 任何建议都很好 我只是不知道该如何让它工作,这似乎是一个简单的想法 当前更新代码:C# datagrid迭代更新期间弹出状态窗口,c#,datagrid,backgroundworker,C#,Datagrid,Backgroundworker,我花了4个小时在这上面,但完全失败了。 我知道我需要使用BackgroundWorker,但所有教程都提到在运行worker的实际表单上运行进度脚本 我有一个大型datagrid,用户可以使用复选框选择all,然后按UPDATE all 这将使用他们选择的一系列选项更新每个网格。 对于某些用户来说,这可能是5条记录,这算不了什么,但有些用户可能会使用5个选项更新200条记录,这需要大约。。。10-15秒的时间来迭代 我已经尝试了很多运行BGworker的变体,它加载一个FrmLoading.Sh
foreach (DataGridViewRow rowx in dataGridpatients.Rows)
{
//MessageBox.Show(Convert.ToBoolean(rowx.Cells["clnselected"].Value).ToString());
if (Convert.ToBoolean(rowx.Cells["clnselected"].Value) == true)
{
//if cycle has a value.
if (cmbcycle.SelectedIndex != -1)
{
rowx.Cells["clncycletype"].Value = cycle;
rowx.Cells["clnpackscollect"].Value = packs;
}
//if location has a value
if (cmblocation.SelectedIndex != -1)
{
location = Convert.ToInt32(cmblocation.SelectedValue);
rowx.Cells["clnlocation1"].Value = location;
}
if (cmbsize.SelectedIndex != -1)
{
size = Convert.ToInt32(cmbsize.SelectedValue);
rowx.Cells["clnpacksize"].Value = size;
}
if (chkDelivery.Checked == true)
{
rowx.Cells["clnDelivery"].Value = true;
}
if (chkSignSheet.Checked == true)
{
rowx.Cells["clnSigningSheet"].Value = true;
}
}
countupdated++;
}
foreach (DataGridViewRow row in dataGridpatients.Rows)
{
row.Cells["clnselected"].Value = false;
row.DefaultCellStyle.BackColor = Color.White;
}
cmbsize.SelectedIndex = -1;
cmblocation.SelectedIndex = -1;
cmbcycle.SelectedIndex = -1;
chkDelivery.Checked = false;
chkSignSheet.Checked = false;
@countupdated++;
我还选择了@count
我想做的是运行上面的代码,但是有一个弹出的覆盖对话框,上面有我的徽标+更新X%
其中X=countupdated/countselected*100
我现在知道我需要使用后台工作程序来调用上述内容,但实际上我不知道如何调用网格并从那里开始。
我知道我需要调用我正在使用的变量
例如,cmbcycle.SelectedIndex
我知道遍历150条记录并更新单个单元格可能是错误的
我的另一个选项是从数据表上的选定单元格创建数据表
然后通过SQL运行更新,而不是遍历绑定表。
然后,在SQL之后,我可以重新创建表,该表现在将更新其中的新单元格值?
这样做是否更合适
此表上的最大行数为200。平均70左右,所以我们永远不会谈论500或1000
编辑:
因此,选中的答案可以运行后台工作程序并引用表单上的控件。
问题是,如果我这样做:
backgroundWorker1.RunWorkerAsync();
splashy.ShowDialog();
splashy.ShowDialog();
backgroundWorker1.RunWorkerAsync();
然后在后台工作程序结束后弹出启动屏幕
如果我这样做:
backgroundWorker1.RunWorkerAsync();
splashy.ShowDialog();
splashy.ShowDialog();
backgroundWorker1.RunWorkerAsync();
然后弹出窗口半自动形成并挂起,直到后台工作程序结束,此时它关闭
由于RunWorkerCompleted事件
编辑:
我没有更新DoWork中的代码,也没有使用调用来引用控件。
这是可行的,代码运行良好
我现在需要一个弹出窗口来显示更新的进度
splashy.InvokeBy(() =>
{
splashy.Show();
});
backgroundWorker1.RunWorkerAsync();
不起作用。它会导致弹出,但会冻结
splashy.ShowDialog();
backgroundWorker1.RunWorkerAsync();
允许对话框显示非“冻结”和扭曲,但实验室lblprogress不更新
这是因为表单永远不会到达RunWorker方法,它被困在ShowDialog中。最好对数据源本身进行修改,然后将其与DataGridView绑定 但是,与现有代码一样,如果您希望访问控件/UI以更新或更改BackgroundWorker.RunWorkerAsync方法或任何其他线程调用中的值,您可以创建一个扩展方法来。调用控件如下:
public static class MyExtensions
{
public static void InvokeBy(this Control ctl, MethodInvoker method)
{
if (ctl.InvokeRequired)
ctl.Invoke(method);
else method();
}
}
为了方便起见,将这个静态类保持在与主类相同的命名空间下
因此,该代码:
foreach (DataGridViewRow rowx in dataGridpatients.Rows)
{
//your codes
}
将成为:
dataGridpatients.InvokeBy(() =>
{
foreach (DataGridViewRow rowx in dataGridpatients.Rows)
{
//your codes
}
});
cmbcycle.InvokeBy(() =>
{
if (cmbcycle.SelectedIndex != -1)
{
//your codes
}
});
同样地
if (cmbcycle.SelectedIndex != -1)
{
//your codes
}
将成为:
dataGridpatients.InvokeBy(() =>
{
foreach (DataGridViewRow rowx in dataGridpatients.Rows)
{
//your codes
}
});
cmbcycle.InvokeBy(() =>
{
if (cmbcycle.SelectedIndex != -1)
{
//your codes
}
});
这样,您可以安全地访问控件,同时保持UI的响应性。用同样的方法更新你的弹出状态界面 这个答案是基于o_o的答案 主要的问题是,我希望UI能够真正更新,后台工作人员能够提供启动 我没有运行BGW中的所有“硬代码”,而是将其保留在原始线程中,但调用了BGW以显示弹出对话框表单 因此,在我使用的硬代码开始时:
backgroundWorker1.RunWorkerAsync();
这就是:
FrmSplash splashy;
private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
splashy = new FrmSplash();
splashy.ShowDialog();
}
为了删除对话框,在GUI线程的代码末尾,我使用了:
splashy.InvokeBy(() =>
{
splashy.Close();
}
);
backgroundWorker1.CancelAsync();
它使用O_O提供的扩展
public static class MyExtensions
{
public static void InvokeBy(this Control ctl, MethodInvoker method)
{
if (ctl.InvokeRequired)
ctl.Invoke(method);
else method();
}
}
我还在splashy中构建了一个标签更新
这样我就可以打电话了
splashy.InvokeBy(() =>
{
splashy.SetStatus(countupdated.ToString());
}
);
当我遍历datagridview行时。这更新了启动屏幕上的标签:在使用BackgroundWorker或Thread时,您需要调用.Invoke或.BeginInvoke来访问控件并执行应该显示在UI上的操作。下面是一个让你开始使用sameThanks@o_o-的例子,因为在我的例子中,我会调用我拥有的4个组合框。然后调用datagrid?因此,我在后台工作程序中运行处理代码,然后更新调用的datagrid?任何controlDataGridView、ComboBox、Textbox等。。。它可能属于BackgroundWorker.RunWorkerAsync方法,需要使用.Invoke调用。外行术语:你的应用程序的UI在一个UI线程上运行。你可以创建任意多的线程,bgw,你可能喜欢。但是如果你
ant要访问控件,从线程/bgw u创建,您必须使用/Thank mate请求许可,我只需要给它一个通行证,对我来说似乎太复杂了。我可以看到如何调用变量,但看不到如何调用整个表,以便可以遍历特定行。。或者只向后台工作人员发送一个数据表??告诉你什么,编辑你的问题以及相关代码,并提及你在使用BGW访问控件时面临的问题。您可以在代码中插入注释以提供进一步的见解。希望我能以这种方式更好地帮助你。如果不是我,其他人可能会:我先试一试。我已经设置了一个数据源并将其绑定到表单上,所以用另一种方式做可能更明智,但我会同时做这两件事,这样我就可以学习了。感谢您的时间。/因此,即使在cmbcycle.InvokeBy部分,我也会遇到一个错误:COmbobox不包含定义InvokeBy我不需要使用invokenew Methodinvokerdelegate等吗?如果我改为.invoke而不是invokeby,我将无法将lambda类型转换为delegateMake静态类,如第一个代码块所示。然后您可以访问。InvokeBy。我更新了我的答案谢谢,我上课的地方错了,因为我是个白痴。那样做了。而在每一个结尾都应该是;还有,是吗?我给你一个机会是的,你是对的,我改正了。也不要强调,学习和理解新事物需要一些时间。跟着我做就行了。耐心地调试,如果你发现一些错误,因为我会出去一段时间。希望在我回来的时候你能找到一个解决方案:否则我们会解决的。很高兴你自己解决了。我几乎忘记了这件事,因为我生病了,很抱歉,在拔完头发后,我请了两天假,然后又回来了haha@o_O是否有方法将invokeby作为控件发送给另一个方法。我有一些方法,我想从中调用splashy。。通过使用InvokeBy,该方法不起作用,没有实例,即使我在方法的顶部有FrmSplashy splashy。你不必发送它。保持静态类公共,即public static void invokebyth此控件ctl、MethodInvoker方法,然后您可以从任何地方访问.InvokeBy。它应该按照预期的那样工作,谢谢,我知道它在我使用的表单中工作,但我有一个公共方法实用程序。addpacks public static void initpacksobject sender,EventArgs e,string formname。我想发送splashy,所以我可以调用它,但是splashy不是UI线程的一部分,它是BGW线程的一部分:P有什么想法吗?