【问题标题】:BackgroundWorker ReportProgress no loop just long database operationBackgroundWorker ReportProgress 没有循环只是长时间的数据库操作
【发布时间】:2014-04-16 12:59:33
【问题描述】:

我有 .NET 4.5 Windows 窗体应用程序,其中一种方法需要一段时间才能完成(它是一个 BulkCopy 函数,它加载大量数据并推送到 SQL 中)。

我想使用 BackgroundWorker 和 ReportProgress,以便用户知道发生了什么事。我制作了一些使用它的应用程序,但是当 BackgroundWorker 工作时,它们都处于某种循环中,我可以轻松地在每个循环步骤中报告进度。

这里我有一个问题,因为没有循环,代码步骤是:

  1. worker 启动异步
  2. 将数据从 DB2 获取到数据表中(这花费的时间最多)
  3. SqlBulk 将数据表复制到 SQL 表中

我需要在第 1 步和第 2 步之间开始报告进度(尽管是一个虚假的进度百分比,一个简单的旋转进度条就足够了),并在第 3 步之后结束报告进度。

任何人都有类似的问题/解决方案,我想我可以只显示一个 GIF 图像并在工作完成后将其隐藏,但我认为这将不起作用,因为表单冻结(没有响应消息)。

【问题讨论】:

  • @huMpty duMpty:这不是一个特定的编码问题,我一直在寻找解决方案,为了获得更多可见性,我标记了 c# 和 vb.net。

标签: c# vb.net winforms


【解决方案1】:

您可以使用 ProgressBar 的 Marquee 样式来显示活动进程的不确定长度:

BackgroundWorker bgw = new BackgroundWorker();
bgw.DoWork += bgw_DoWork;
bgw.RunWorkerCompleted += bgw_RunWorkerCompleted;
progressBar1.Style = ProgressBarStyle.Marquee;
progressBar1.MarqueeAnimationSpeed = 50;
bgw.RunWorkerAsync();

void bgw_DoWork(object sender, DoWorkEventArgs e) {
  // long work
}

void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
  progressBar1.Style = ProgressBarStyle.Continuous;
  progressBar1.MarqueeAnimationSpeed = 0;
}

【讨论】:

  • 太好了,这就是我要找的,简单又快速,谢谢!
【解决方案2】:

最简单的解决方案是在表单上显示动画 GIF 图像。只要工作在后台线程中正确完成,表单就不会冻结动画。如果表单仍然冻结,这意味着它实际上并没有像您想象的那样在后台线程上进行工作。或者,您可以使用计时器定期更新另一种控件,例如进度条。

【讨论】:

    【解决方案3】:

    您是否考虑过使用计时器/线程或自定义事件。 您可以在计时器事件处理程序中更新用户通知消息

     try  {
            // Start a Timer                     
           // Write from the source to the destination.
                    bulkCopy.WriteToServer(reader);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
                finally
                {
                    // Close the SqlDataReader. The SqlBulkCopy 
                    // object is automatically closed at the end 
                    // of the using block.
                    reader.Close();
                   // Stop the Timer
                }
    

    【讨论】:

      【解决方案4】:

      还有另一种解决方案可以报告更准确的进度百分比:

          private DataTable dt = new DataTable();
      
          void Start()
          {
              dt.RowChanged += new DataRowChangeEventHandler(dt_RowChanged);
              progressBar1.Maximum = dtRowsCount;
              bgWorker.RunWorkerAsync();
          }
      
          void dt_RowChanged(object sender, DataRowChangeEventArgs e)
          {
              bgWorker.ReportProgress(1);
          }
      
          void bgWorker_DoWork(object sender, DoWorkEventArgs e)
          {
              //Your work
          }
      
          void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
          {
              progressBar1.Value += e.ProgressPercentage;
          }
      

      【讨论】:

      • 有趣的解决方案,第一次调用 SELECT COUNT(*) 获取 dtRowsCount 时会有一点延迟,但这应该不是什么大问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多