我有一个类从大文件(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'正在使用行号更新标签,但它没有做任何事情。 出于某种原因,在调试模式下,我看到两者都正确更新,所以我怀疑一些线程问题。
我希望我能够以清晰的方式呈现这一切。
解决问题的方法:
标签未更新是由于频繁拨打电话(有关详细信息,请参阅下面此问题的答案)。我把方法改为:
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;
}
答案 0 :(得分:3)
您经常调用ReportProgress。比每秒大约一千次更频繁地调用它,并且UI线程被调用请求所淹没,它不再能够解决它的常规任务。它停止绘画并注意用户输入。更新仍然会发生,你再也看不到它们了。
这当然是因为你在内部循环中有ReportProgress,为数据集中的每一行调用它。这是浪费精力,人眼无法跟上这种更新速度,每秒超过20次更新的任何东西看起来都很模糊。 Q&amp; D修复将是每第100行调用ReportProgress。注意经过的时间并计算45毫秒是可以在任何机器上运行的修复。
进度条的问题听起来像一个计算问题,这个问题在片段中并不明显。进度条工作但不是文本更新的原因是PB旨在避免此绘制问题,它在Value属性更改时强制重绘,而不是等待Windows传递Paint通知。
答案 1 :(得分:0)
而不是慢慢地从0移动到100 一次,进度条从0移动到 快几次100。
您是否将进度条的Minimum
和Maximum
设置为0和100?
WPF ProgressBar is 0 and 1的默认值。
如果您使用的是WinForms进度条the default is 0 and 100,那应该不是问题。