好的,这里是:我有一个应用程序的一部分,用于查询数据库中的行。当用户在搜索框中输入文本时(或者改变另一个过滤器设置),我执行查询。确保异步任务在重新启动该任务之前已完全取消
从数据库返回的数据将进入绑定到DataGrid的ObservableCollection。因为我意识到保持UI响应,我使用Async-Await(尝试)在后台填充此ObservableCollection。我想要取消正在进行的任务等待它确认取消,然后“重新启动”(或更确切地说,创建一个新的任务)与新的设置。
但我得到各种奇怪的结果(尤其是当我减慢任务模拟慢数据库访问),如收集没有得到清除和两次填充和处置CancellationTokenSource(我读取的是一个好主意),有时当我打电话给Cancel()
时,它已被处置,同时我得到一个例外。
我怀疑这个问题源于我对这个模式的理解存在根本性的差距,因此任何样式/模式指针都像实际的技术解决方案一样受欢迎。
的代码基本上是这样的:
ObservableCollection<Thing> _thingCollection;
Task _thingUpdaterTask;
CancellationTokenSource _thingUpdaterCancellationSource;
// initialisation etc. here
async void PopulateThings(ThingFilterSettings settings)
{
// try to cancel any ongoing task
if(_thingUpdaterTask?.IsCompleted ?? false){
_thingUpdaterCancellationSource.Cancel();
await _thingUpdaterTask;
}
// I'm hoping that any ongoing task is now done with,
// but in reality that isn't happening. I'm guessing
// that's because Tasks are getting dereferenced and
// orphaned in concurrent calls to this method?
_thingCollection.Clear();
_thingUpdaterCancellationSource = new CancellationTokenSource();
var cancellationToken = _thingUpdaterCancellationSource.Token;
var progressHandler = new Progress<Thing>(x => _thingCollection.add(x));
var progress = (IProgress<Thing>)progressHandler;
try{
_thingUpdaterTask = Task.Factory.StartNew(
() => GetThings(settings, progress, cancellationToken));
await _thingUpdaterTask;
}catch(AggregateException e){
//handle stuff etc.
}finally{
// should I be disposing the Token Source here?
}
}
void GetThings(ThingFilterSettings settings,
IProgress<Thing> progress,
CancellationToken ctok){
foreach(var thingy in SomeGetThingsMethod(settings)){
if(ctok.IsCancellationRequested){
break;
}
progress.Report(thingy);
}
}
'await'展开异常,无需捕获'AggregateException'。 – xxbbcc
@dymanoid - 当我尝试推广我的代码的例子时,我犯了一个错字。修复并希望现在有意义! – LexyStardust
@LexyStardust不使用'async void',除了事件处理程序。你应该更新该方法返回'任务' – Nkosi