BackgroundWorker.ReportProgress报告错误的值

时间:2011-04-19 11:43:19

标签: c# backgroundworker

我有一个类从大文件(100,000)行中提取字符串,并希望向用户提供一些进度反馈。我的问题是没有正确报告进展情况。

我使用自定义类发送UserState属性:

public enum UpdateType {FileCount, ProcessedFiles, LineCount, ProcessedLines, StepUpdate};
public class ProgressUpdate
{
        public UpdateType UpdateType { get { } set { } }
        public string Update { get { } set { } }
}

这是我处理ReportProgress事件的方法:

public class BGWorkerBase : BackgroundWorker
{
    public void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        ProgressUpdate update;
        update = (ProgressUpdate)e.UserState;
        switch (update.UpdateType)
        {
            case UpdateType.FileCount:
                MainWindow.FrmDisplayProgress.FileCount = update.Update;
                break;

            case UpdateType.ProcessedFiles:
                MainWindow.FrmDisplayProgress.FileProgress = update.Update;
                break;

            case UpdateType.LineCount:
                MainWindow.FrmDisplayProgress.LineCount = update.Update;
                break;

            case UpdateType.ProcessedLines:
                MainWindow.FrmDisplayProgress.LineProgress = update.Update;
                MainWindow.FrmDisplayProgress.PrecentProgress = e.ProgressPercentage;
                break;

            case UpdateType.StepUpdate:
                MainWindow.FrmDisplayProgress.AddLine(update.Update);
                break;
        }
    }
}

MainWindow.FrmDisplayProgress是对显示进度的表单的调用。 最后,这是工人阶级:

public class TraceFile
{
    public HashSet<string> ExtractValues(HashSet<MyRegex> regexList, BackgroundWorker worker)
    {
        HashSet<string> results = new HashSet<string>();
        int rowNumber = 1;

        foreach (DataRow row in Lines.Rows)
        {
            int percentComplete = (int)(((float)rowNumber / (float)Lines.Rows.Count) * 100);
            worker.ReportProgress(percentComplete, new ProgressUpdate(UpdateType.ProcessedLines, rowNumber++.ToString()));

            // using multiple regex supports different formats for the same data type. For example - more then 1 account format
            foreach (MyRegex regex in regexList)
            {
                MatchCollection matches = regex.Matches(row["Text"].ToString());
                if (matches.Count > 0)
                {
                    foreach (Match result in matches)
                        results.Add(result.ToString());
                }
            }
        }

        return results;
    }
}

捕获这些特定类型的更新的情况如下:

case UpdateType.ProcessedLines:
                    MainWindow.FrmDisplayProgress.LineProgress = update.Update;
                    MainWindow.FrmDisplayProgress.PrecentProgress = e.ProgressPercentage;
                    break;

'MainWindow.FrmDisplayProgress.PrecentProgress = e.ProgressPercentage;'正在更新进度条。进度条不是从0缓慢地从0移动到100,而是快速从0快速移动到100。 'MainWindow.FrmDisplayProgress.LineProgress = update.Update'正在使用行号更新标签,但它没有做任何事情。 出于某种原因,在调试模式下,我看到两者都正确更新,所以我怀疑一些线程问题。

我希望我能够以清晰的方式呈现这一切。

解决问题的方法:

  1. 多次运行的进度条是红色鲱鱼,与问题无关。这种情况发生的原因是该方法多次进入。
  2. 标签未更新是由于频繁拨打电话(有关详细信息,请参阅下面此问题的答案)。我把方法改为:

    public HashSet<string> ExtractValues(HashSet<MyRegex> regexList, BackgroundWorker worker)
    {
        HashSet<string> results = new HashSet<string>();
        int rowNumber = 0;
        DateTime startCount = DateTime.Now;
        DateTime endCount = DateTime.Now;
    
        foreach (DataRow row in Lines.Rows)
        {
            rowNumber++;
            TimeSpan timeSpan = endCount.Subtract(startCount);
            if ((timeSpan.Milliseconds > 50) | (rowNumber == Lines.Rows.Count))
            {
                int percentComplete = (int)(((float)rowNumber / (float)Lines.Rows.Count) * 100);
                worker.ReportProgress(percentComplete, new ProgressUpdate(UpdateType.ProcessedLines, rowNumber.ToString()));
                startCount = DateTime.Now;
            }
    
            // using multiple regex supports different formats for the same data type. For example - more then 1 account format
            foreach (MyRegex regex in regexList)
            {
                MatchCollection matches = regex.Matches(row["Text"].ToString());
                if (matches.Count > 0)
                {
                    foreach (Match result in matches)
                        results.Add(result.ToString());
                }
            }
    
            endCount = DateTime.Now;
        }
    
        return results;
    }
    

2 个答案:

答案 0 :(得分:3)

您经常调用ReportProgress。比每秒大约一千次更频繁地调用它,并且UI线程被调用请求所淹没,它不再能够解决它的常规任务。它停止绘画并注意用户输入。更新仍然会发生,你再也看不到它们了。

这当然是因为你在内部循环中有ReportProgress,为数据集中的每一行调用它。这是浪费精力,人眼无法跟上这种更新速度,每秒超过20次更新的任何东西看起来都很模糊。 Q&amp; D修复将是每第100行调用ReportProgress。注意经过的时间并计算45毫秒是可以在任何机器上运行的修复。

进度条的问题听起来像一个计算问题,这个问题在片段中并不明显。进度条工作但不是文本更新的原因是PB旨在避免此绘制问题,它在Value属性更改时强制重绘,而不是等待Windows传递Paint通知。

答案 1 :(得分:0)

  

而不是慢慢地从0移动到100   一次,进度条从0移动到   快几次100。

您是否将进度条的MinimumMaximum设置为0和100? WPF ProgressBar is 0 and 1的默认值。

如果您使用的是WinForms进度条the default is 0 and 100,那应该不是问题。