Backgroundworker ReportProgress延迟

时间:2014-05-14 06:53:51

标签: c# winforms backgroundworker

我遇到了backgroundworker的reportprogress函数问题。我在worker的doWork函数中使用odbc驱动程序读取数据记录,在我读取的每一行之后,我调用reportProgress函数将此行添加到显示器。有时候这有效,有时报告进度会等到我读取任意数量的记录,例如6,然后添加6条与最后一条记录相同的记录。因此,例如在以下代码的打印中,我得到的结果如下:

ROW: 1: 00000001
ABS 1: 00000001
ROW: 2: 00000002
ROW: 3: 00000003
ROW: 4: 00000010
ROW: 5: 00000011
ROW: 6: 00000012
ROW: 7: 00000013
ROW: 8: 00000014
ROW: 9: 00000015
ROW: 10: 00000015
ABS 10: 00000015
ABS 10: 00000015
ABS 10: 00000015
ROW: 11: 00000016
ABS 11: 00000016
ABS 11: 00000016
ABS 11: 00000016
ABS 11: 00000016
ABS 11: 00000016
ABS 11: 00000017
ROW: 12: 00000017
ABS 12: 00000017
ABS 12: 00000017

在我调用报告进度后,有人建议使用Thread.sleep,但我不想这样做。

这是我在DoWork中的代码:

while (!terminateRead)
{
    if (reader.Read())
    {
        try
        {
            for (int i = 0; i < columnCount; i++)
            {
                if (reader != null)
                {
                    row[i] = reader.GetString(i);
                }
            }
        }
        catch (Exception e)
        {
            Console.WriteLine("Read Process interrupted");
        }
        currentRow++;
        double perc = ((double)currentRow / rowCount) * 100.0;
        int percentageComplete = Convert.ToInt32(perc);
        Console.WriteLine("ROW: " + currentRow + ": " + row[0]);
        backgroundWorker1.ReportProgress(percentageComplete, row);
    }   

并在我的报告进度中

/* Function to display the progress percentage to the user and add rows copied
 * from the Btrieve table to the view.
 * */
private void backgroundWorker1_ProgressChanged(object sender,   ProgressChangedEventArgs e)
{
    // string array of the data read in the populateRows() function.
    string[] row = (string[])e.UserState;
    progressBar1.Value = e.ProgressPercentage;
    label1.Text = "Loaded " + e.ProgressPercentage + "% (" + currentRow + "\\" + rowCount + ") of the file";
    dataGridView1.Rows.Add(row);
    Console.WriteLine("ABS " +currentRow + ": " + row[0]);
    //dataGridView1.Rows[currentRow-1].HeaderCell.Value = (currentRow).ToString();
}

2 个答案:

答案 0 :(得分:1)

MSDN

中所述
  

对ReportProgress方法的调用是异步的并返回   立即。 ProgressChanged事件处理程序在线程上执行   创建了BackgroundWorker。

因此,后台工作程序不会等待处理ProgressChanged事件并继续读取行和引发事件。另一方面,所有处理程序都在你的主线程上执行,这有另一个工作要做,所以它们只是安排好了。另请注意,处理此事件可能需要花费更多时间,而不是在处理过程中执行一个步骤。这就解释了为什么处理速度更快。

但为什么要分批处理?线程不执行某些方法并退出 - 它们有一些时间来完成工作。这就是为什么你会看到连续执行多个处理程序的原因 - 它只是给主线程进行处理的时间窗口。如果有多个处理程序等待执行,它们都会开始执行。

最后一件事是currentRow问题。在处理程序中,您会看到已处理的最后一行的currentRow值,因为您在两个线程中使用相同的变量。处理程序无法猜出事件被引发时currentRow的值是什么,直到您将该值传递给处理程序。如果您不想创建用于在线程之间传递这些参数的类,则可以使用简单数组或动态:

 backgroundWorker1.ReportProgress(percentage, new object[]{ currentRow, row });

然后在处理程序中,您可以从事件发生时获得currentRow值:

 object[] state = (object[])e.UserState;
 string[] row = (string[])state[1];
 int currentRow = (int)state[0];

不要忘记将currentRow本地设置为DoWork处理程序 - 它不应该是表单中的全局变量。

答案 1 :(得分:1)

不要在Console.WriteLine()方法中使用DoWork(),它应该是RunWorkerCompleted事件处理程序或ReportProgress方法的一部分。 DoWork方法的工作应该是处理长时间运行的工作或报告进度,它应该 与GUI线程交互(就像它不应该调用控制台方法)。

请将此行移出DoWork()方法并调用backgroundWorker1_ProgressChangedRunWorkerCompleted事件处理程序(如果尚未添加,则需要添加事件处理程序):

Console.WriteLine("ROW: " + currentRow + ": " + row[0]);

有关BackgroundWorker组件的更多信息,请参阅: