Hello开发人员,
我正面临一个轻微的困境。我有一个WPF应用程序,它读取一个相当大的Excel文件,然后将其作为XML文件输出。我面临的问题是我想将操作的进度报告给处理程序。
我无法顺利工作"顺利地#34;,字面意思是GUI线程中的进度条立即被填充,然后立即填充保存从Excel文件读取的内容的DataGrid。
我是Async / Await / Task的新手,我到目前为止一直在使用BackgroundWorker,但我希望获得更多关于此的知识,所以如果这是一个愚蠢的问题,我很抱歉。
我已阅读来自here.
的Stephen Cleary的教程老实说,我不知道为什么进度条不能顺利填补#34;应该是......
在GUI中调用的代码:
var progress = new Progress<int>(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)
的方法主体:
public DataTable ReadFileContent(string filePath, IProgress<int> 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;
}
}
提前谢谢!
答案 0 :(得分:6)
首先,让我们摆脱危险的ContinueWith
电话。你真的应该使用await
代替:
var progress = new Progress<int>(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<int>
处理程序需要progressPercent
,但ReadFileContent
正在发送已读取的行数,不是一个百分比。所以,要解决这个问题:
if (currentIndex % percentageProgress == 0)
progress?.Report(row * 100 / totalRows);
(此处还有其他几个选项;例如,如果您想要更高级的用户界面,则可以决定报告当前行和总行数。)
进度条不能“顺利”填充,因为它应该是
我上面描述的是最低可接受的解决方案。特别是,“仅更新10次”代码有点问题;无论更新的速度有多快或多慢,它总是会更新10次。更通用的解决方案是使用基于Rx的IProgress
解决方案,这将允许您根据时间进行限制(例如,每秒4次更新)。