报告Async Task的进度

你好开发者,

我面临着一个轻微的困境。 我有一个WPF应用程序,它读取一个相当大的Excel文件,然后将其作为XML文件输出。 我面临的问题是我想将操作的进度报告给处理程序。

我无法让它“顺利”工作,字面意思是GUI线程中的进度条立即被填充,然后立即填充保存从Excel文件读取的内容的DataGrid。

我是Async / Await / Task的新手,我一直在使用BackgroundWorker,但我希望能够获得更多关于此的知识,所以如果这是一个愚蠢的问题,我很抱歉。

我从这里读过Stephen Cleary的教程。

老实说,我不知道为什么进度条不能“顺利”填充,因为它应该……

在GUI中调用的代码:

var progress = new Progress(progressPercent => pBar.Value = progressPercent); Task.Run(() => _sourceService.ReadFileContent(filePath, progress)).ContinueWith(task => { dataGrid.ItemsSource = task.Result.DefaultView; DataTable = task.Result; if (DataTable.Rows.Count > 0) BtnCreateXmlFile.IsEnabled = true; }, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext()); 

ReadFileContent(filePath, progress)的方法体ReadFileContent(filePath, progress)

 public DataTable ReadFileContent(string filePath, IProgress progress) { var rowStart = 7; var columnStart = 1; var existingFile = new FileInfo(filePath); using (var package = new ExcelPackage(existingFile)) { var worksheet = package.Workbook.Worksheets["BOP"]; var dt = new DataTable(); // Compose the name of the table from: // - Product Type // - Customer // - Customer Project // * These can be found in the "CollaborationContext" sheet that is present in the ExcelFile. if (package.Workbook.Worksheets["CollaborationContext"].SelectedRange["B6"].Value.Equals("object_type")) { dt.TableName = package.Workbook.Worksheets["CollaborationContext"].SelectedRange["C9"].Value + " " + package.Workbook.Worksheets["CollaborationContext"].SelectedRange["D9"].Value + " " + package.Workbook.Worksheets["CollaborationContext"].SelectedRange["E9"].Value; } dt.TableName = package.Workbook.Worksheets["CollaborationContext"].SelectedRange["B9"].Value + " " + package.Workbook.Worksheets["CollaborationContext"].SelectedRange["C9"].Value + " " + package.Workbook.Worksheets["CollaborationContext"].SelectedRange["D9"].Value; // Report only in chunks. We do not want to call `progress.Report` for each row that is read. var totalRows = worksheet.Dimension.End.Row; var currentIndex = 0; var percentageProgress = totalRows / 10; // Get Columns and add them to the DataTable for (var col = columnStart; col <= worksheet.Dimension.End.Column - 1; col++) dt.Columns.Add(worksheet.Cells[6, col].Value.ToString()); // Place data into DataTable for (var row = rowStart; row <= worksheet.Dimension.End.Row; row++) { var dr = dt.NewRow(); var x = 0; currentIndex++; for (var col = columnStart; col <= worksheet.Dimension.End.Column - 1; col++) { dr[x++] = worksheet.Cells[row, col].Value; } dt.Rows.Add(dr); // Report progress back to the handler if (currentIndex % percentageProgress == 0) progress?.Report(row); } return dt; } } 

先感谢您 !

首先,让我们摆脱危险的ContinueWith调用。 你真的应该使用await

 var progress = new Progress(progressPercent => pBar.Value = progressPercent); var result = await Task.Run(() => _sourceService.ReadFileContent(filePath, progress)); dataGrid.ItemsSource = result.DefaultView; DataTable = result; if (DataTable.Rows.Count > 0) BtnCreateXmlFile.IsEnabled = true; 

接下来,您可能会看到进展的问题是您的Progress处理程序期望progressPercent ,但ReadFileContent正在发送它读取的行数, 而不是百分比。 所以,要解决这个问题:

 if (currentIndex % percentageProgress == 0) progress?.Report(row * 100 / totalRows); 

(此处还有其他几个选项;例如,如果您想要更高级的用户界面,您可以决定报告当前行总行数)。

进度条没有按照应有的“顺利”填写

我上面描述的是最低可接受的解决方案。 特别是,“仅更新10次”代码有点问题; 无论更新的速度有多快或多慢,它总是会更新10次。 更通用的解决方案是使用基于Rx的IProgress解决方案,它允许您根据时间进行限制(例如,每秒4次更新)。