取消并启动基于导航的新异步任务
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.
我有一个 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.