확인을 클릭하십시오. 데이터베이스에서 행을 쿼리하는 응용 프로그램의 일부가 있습니다. 사용자가 검색 상자에 텍스트를 입력하거나 다른 필터 설정을 변경할 때 쿼리를 수행합니다.비동기 작업이 해당 작업을 다시 시작하기 전에 완전히 취소되었는지 확인하십시오.
데이터베이스에서 반환되는 데이터는 DataGrid에 바인딩 된 ObservableCollection으로 이동합니다. UI 응답 성을 의식하고 있기 때문에 배경에 ObservableCollection을 채우기 위해 Async-Await (시도)를 사용하고 있습니다.
내 생각에 사용자가 무언가를 입력하거나 필터 설정을 변경할 때마다 진행중인 작업을 취소하고 싶습니다. 취소가 완료 될 때까지 기다렸다가을 확인한 다음 새로운 작업)을 새 설정으로 변경하십시오.
하지만 수집이 취소되지 않고 두 번 채워지고 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 '를 사용하지 않습니다. 그 메소드를 업데이트하여'Task'를 리턴해야합니다. – Nkosi