BackgroundWorker报告进度,无循环只有长时间的数据库操作

5
我有一个.NET 4.5 Windows Forms应用程序,其中一个方法需要一段时间才能完成(它是一个BulkCopy函数,它加载大量数据并将其推入SQL)。
我想使用BackgroundWorker和ReportProgress,这样用户就会知道有事情正在发生。我制作了一些使用此功能的应用程序,但当BackgroundWorker在工作时,它们都处于某种循环中,并且我可以轻松地在每个循环步骤内报告进度。
但这里我有一个问题,因为没有循环,代码步骤如下:
1.异步启动worker 2.从DB2获取数据到datatable(这需要最长时间)
3.SqlBulkCopy datatable插入SQL表
我需要在步骤1和步骤2之间开始报告进度(即使是虚假的进度百分比,一个简单的旋转进度条也足够了),并在步骤3之后结束报告进度。
有人遇到过类似的问题/解决方案吗?我想我只能显示一个GIF图像并在工作完成后隐藏它,但我认为这不起作用,因为表格会冻结(无响应消息)。

@huMpty duMpty:这不是一个特定的编码问题,我正在寻找一个解决方案,为了更好的可见性,我标记了C#和VB.NET。 - Iztoksson
4个回答

4

您可以使用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;
}

太好了,这正是我在寻找的,简单快捷,谢谢! - Iztoksson

2

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


1
你想过使用定时器/线程或自定义事件吗?你可以在定时器事件处理程序中更新用户通知消息。
 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
            }

1

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

    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时可能会有轻微延迟,但这不应该是一个大问题。 - Iztoksson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接