У меня есть класс, извлекающий строки из большого файла (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 до 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;
}