C# datagrid迭代更新期间弹出状态窗口

C# datagrid迭代更新期间弹出状态窗口,c#,datagrid,backgroundworker,C#,Datagrid,Backgroundworker,我花了4个小时在这上面,但完全失败了。 我知道我需要使用BackgroundWorker,但所有教程都提到在运行worker的实际表单上运行进度脚本 我有一个大型datagrid,用户可以使用复选框选择all,然后按UPDATE all 这将使用他们选择的一系列选项更新每个网格。 对于某些用户来说,这可能是5条记录,这算不了什么,但有些用户可能会使用5个选项更新200条记录,这需要大约。。。10-15秒的时间来迭代 我已经尝试了很多运行BGworker的变体,它加载一个FrmLoading.Sh

我花了4个小时在这上面,但完全失败了。 我知道我需要使用BackgroundWorker,但所有教程都提到在运行worker的实际表单上运行进度脚本

我有一个大型datagrid,用户可以使用复选框选择all,然后按UPDATE all 这将使用他们选择的一系列选项更新每个网格。 对于某些用户来说,这可能是5条记录,这算不了什么,但有些用户可能会使用5个选项更新200条记录,这需要大约。。。10-15秒的时间来迭代

我已经尝试了很多运行BGworker的变体,它加载一个FrmLoading.Showdialog

或者尝试让BGworker运行代码,然后让主线程运行FrmLoading.Show 然而,一切都不起作用

如果我在后台工作程序中有更新代码,它会失败,因为datagrid和所有内容都在不同的线程中

另一方面,它只是挂在FRM加载。显示

任何建议都很好

我只是不知道该如何让它工作,这似乎是一个简单的想法

当前更新代码:

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有什么想法吗?