【发布时间】:2017-02-01 00:31:43
【问题描述】:
各位开发者您好,
我面临着一个小小的困境。我有一个 WPF 应用程序,它读取一个相当大的 Excel 文件,然后将其输出为 XML 文件。我面临的问题是我想将操作的进度报告给处理程序。
我无法让它“顺利”工作,实际上,GUI 线程中的进度条会立即被填满,然后保存从 Excel 文件读取的内容的 DataGrid 会立即被填满。
我是 Async/Await/Task 的新手,直到现在我一直在使用 BackgroundWorker,但我希望获得更多关于这方面的知识,所以如果这是一个愚蠢的问题,我很抱歉。
我已经阅读了here.Stephen Cleary 的教程
老实说,我不知道为什么进度条没有按应有的“平滑”填充...
在 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;
}
}
提前谢谢你!
【问题讨论】:
-
Excel 文件有多少行?一旦您到达第 100 行,进度条就会显示为 100,因为这是您在
progress?.Report()中报告的数字。或类似的东西。我真的不明白if (currentIndex % percentageProgress == 0),但也许我需要更仔细地阅读。 -
您好,已读取 805 行。哦等等,我是否必须将进度条的最大值设置为高于总行数?!
-
这取决于你。如果您不想这样做,可以报告百分比而不是行索引。
-
您说的完全正确,我注意到我将
row传递给了 ReportProgress 方法。问题是,我如何找出百分比,我尝试使用:` if (currentIndex % percentProgress == 0) progress?.Report(row);` -
1) 你应该
awaiting 你正在创建的任务 2) 你应该避免Task.Run()当工作将是 I/O-bound 3) 你的进度pBar.Value = progressPercent委托未在 UI 线程上执行,因此不会更新
标签: c# wpf asynchronous task