我遇到了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();
}
答案 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_ProgressChanged
或RunWorkerCompleted
事件处理程序(如果尚未添加,则需要添加事件处理程序):
Console.WriteLine("ROW: " + currentRow + ": " + row[0]);
有关BackgroundWorker组件的更多信息,请参阅: