取消并启动基于导航的新异步任务

cancel and start a new async task based on navigation

我有一个 WPF 表单,它的屏幕被分成两部分作为主从表单。上面的部分是 master,它显示了数据网格中的一堆记录,数据绑定到 collectionviewsource。 每当用户单击一行时,表单的底部就会通过对 collectionviewsource.current_changed 事件的反应而建立起来。 在那里我取消了所有挂起的异步操作,并开始了一个新的操作。 代码是这样的:

if (_tokenSource != null) //_tokenSource is an instance variable of the class that implements current_changed
{
    try
    {
        _tokenSource.Cancel(); //needed because _tokenSource might be disposed already. Ugly.
    }
    catch (Exception Ex)
    {
    }
}

using (_tokenSource = new CancellationTokenSource())
{
    try
    {
        _unitOfWork = await loadRelatieAsync(relatieId, _tokenSource.Token); // this is just currently an await Task.Delay(5000,token).ConfigureAwait(true); return null;
    }
    catch (Exception Ex)
    {
    }
}
//_tokenSource = null; can’t do this, it would lead to several operations not being cancelled

我这里的好像可以用,但是代码很丑,应用还是有点卡顿。有 proper/better 的方法吗?

我通常不会费心处理 CancellationTokenSource。如果你只是覆盖它而不处理它,代码更干净:

if (_tokenSource != null)
  _tokenSource.Cancel();

_tokenSource = new CancellationTokenSource();
try
{
  _unitOfWork = await loadRelatieAsync(relatieId, _tokenSource.Token);
  return null;
}
catch (OperationCanceledException ex)
{
}

关于"sluggishness",我猜测可能是因为用户在主视图中快速更改了所选项目?如果是这样,您可能想要在开始新操作之前引入一个小的(比如 100 毫秒)延迟 before。这可以用 async 代码来完成:

if (_tokenSource != null)
{
  _tokenSource.Cancel();
  _tokenSource = null;
}

var currentItem = _whateverView.CurrentItem;
await Task.Delay(TimeSpan.FromMilliseconds(100));
if (currentItem != _whateverView.CurrentItem)
  return null;

_tokenSource = new CancellationTokenSource();
try
{
  _unitOfWork = await loadRelatieAsync(relatieId, _tokenSource.Token);
  return null;
}
catch (OperationCanceledException ex)
{
}

尽管我必须说,如果您要执行很多 "time-based" 操作(例如 "delay this action for a period of time" 或 "throttle these events based on this time window"),那么更自然的方法是 Reactive Extensions.