【发布时间】:2020-07-17 09:46:19
【问题描述】:
我有 3 个 DataGridView,它们在运行时最多加载 20,000 行(从文件中读取行并将每行加载到三个 DataGridView 中的两个中)。我使用线程使加载方法异步,因为在更改它之前,如果我在主线程中加载了太多行,GUI 会冻结。代码按预期工作。 我可以看到数据网格视图中填充的行,并且可以在读取文件并继续阅读时滚动数据网格视图。
问题是当我关闭表单时,我收到“对象已处理期望”。 请你能帮我解决这个问题吗?我可以捕获异常并关闭表单,但这不是合适的方式。我尝试使用取消令牌源,但是当我再次进入循环时,IsCancelled 属性为 true,即使我添加了一个 if 来检查它,它也会在 Invoke 方法中输入操作。
readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
Task task;
private async void UmpiresList_Load(object sender, EventArgs e)
{
Logger.LogDebug("Loading results to dataGridView");
task = Task.Factory.StartNew(() => LoadResults(), cancellationTokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
await task.ContinueWith(result =>
{
exportToExcelBtn.SetEnabledStatus(true);
copyToClipboardButton.SetEnabledStatus(true);
});
}
//load results to three tabs -> three data grid views
private void LoadResults()
{
foreach(var result in Results)
{
Logger.LogDebug($"Adding row {result.Key}");
AddUmpiresResultsToDataGrid();
AddFinalResultToDataGrid();
}
}
//load results to DataGrid A & B
private void AddUmpiresResultsToDataGrid()
{
//umpires.Count <= 5
foreach(var umpire in umpires)
{
AddToAllResultsDataGrid(umpire);
AddToUmpiresResultsDataGrid(umpire);
}
}
//load results to DataGrid A & C
private void AddFinalResultToDataGrid(int round, MatchResult matchResult)
{
AddToAllResultsDataGrid();
AddToFinalResultsDataGrid();
}
//load results to DataGrid A
private void AddToAllResultsDataGrid()
{
if(cancellationTokenSource.IsCancellationRequested==false){
{
this.Invoke(new Action(() =>
allResultsDGV.Rows.Add(round, competitionMode.Name(), result, extraInfo)));
}
}
//load results to DataGrid B
private void AddToUmpiresResultsDataGrid()
{
if(cancellationTokenSource.IsCancellationRequested==false){
this.Invoke(new Action(() =>
umpiresResultsDGV.Rows.Add(round, competitionMode.Name(),
umpirePoints.Name, umpirePoints.WinnerMessage,
umpirePoints.RedPoints, umpirePoints.BluePoints)));
}
}
//load results to DataGrid C
private void AddToFinalResultsDataGrid()
{
if(cancellationTokenSource.IsCancellationRequested==false){
{
this.Invoke(new Action(() =>
finalResultsDGV.Rows.Add(round,
matchResult.Time.ToString(Logger.DTFormat),
matchResult.CompetitionMode.Name(),
matchResult.GetWinnerMessage(),
matchResult.Red, matchResult.Tie, matchResult.Blue, info1, info2)));
}
}
Form_Closing(Object o, Sender e){
//this should be enough to cancel? how can I abort the async thread?
cancellationTokenSource.Cancel();
}
【问题讨论】:
-
简单地说:在任务完成之前不要关闭表单。
-
@Sinatr 感谢您的快速回复。我不能,因为客户可以决定中止操作。加载 20,000 行只是一个测试,但如果他加载 5,000 个结果,则可能需要几分钟,也许他决定关闭表单并稍后检查结果。
-
当您关闭表单时,您向任务发出信号表明它应该停止,但您并不是在等待任务停止。
-
@Neil 正确。因为我不想等。当用户决定中止操作时,可能需要 5 分钟才能完成。我需要立即完成它,因为表单将被关闭并且加载的数据不相关。我该怎么做?
-
不要通过一个不间断的方法调用加载所有结果。将大作业拆分成较小的批次,并在开始下一批之前检查是否取消。加载 5000 个结果 = 100 个加载 50 个结果。在关闭表单时,您会取消任务,等到它完成后再关闭。
标签: c# multithreading async-await task