2017-07-29 36 views
-1

我需要执行async任务取消。我知道CancellationTokenSource会帮助我实现这一目标。但我无法找到合适的方法。使用CancellationTokenSource取消之前的异步任务

我有一个搜索文本框,每当在文本框一用户类型,对于每个TextChanged事件我请GetStocks方法如下图所示,

public async Task GetStocks() 
{ 
    var stockings = new List<Services.Models.Admin.SiteStockingLevelsModel>(); 
    IsBusy = true; 
    cts?.Cancel(); 
    cts = new CancellationTokenSource(); 
    await Task.Run(() => { CreateStockingCollection(); }); 
    ValidateMaterials(); 
    IsBusy = false; 
} 

被如下所示的CreateStockingCollection方法,

private void CreateStockingCollection() 
{ 
    var stockings = _siteStockingLevelsService.GetSiteInventoryLevels(SiteId); 
    CreateStockingLevelCompareCollection(stockings); 
    StockingLevels = 
     _mapper.Map<TrulyObservableCollection<SiteStockingLevelsModel>>(stockings);    

    ((INotifyPropertyChanged)StockingLevels).PropertyChanged += 
     (x, y) => CompareStockingChanges(); 
    CompareStockingChanges(); 
} 

我的要求是,
示例假设用户想输入“Abc”。当用户键入“A”时,将调用GetStocks方法,用户立即输入“b”,再次调用get stocks方法,在这种情况下,我想取消之前用字母“A”调用的GetStocks任务。

+1

仅供参考:更适合这可能是“被动式扩展”。根据文本更改创建任务事件可以大大改善,例如,如果至少有2个字符,并且搜索文本中没有200毫秒的变化,则只需开始搜索。这将减少昂贵的通话。一个例子可以在这里找到:https://stackoverflow.com/questions/22873541/search-on-textchanged-with-reactive-extensions。 –

+2

@PeterBons有一个很好的观点,但除此之外,您并未在您发布的代码中的任何位置使用该令牌。您需要将CTS的标记传递给任何应该参与合作取消的任务。然后该任务应该检查令牌是否表示操作应该被取消。对于非CPU绑定的操作,除非令牌可以一直向下传递(通常通过使用带取消令牌支持的所有异步调用),否则这是不可能的。这样你可以取消一个长时间运行的数据库查询。 –

+0

这是一个WPF应用程序。 – Vinay

回答

1

取消是合作的,所以你就需要它传递给自己的代码并将其反应到令牌:

public async Task GetStocks() 
{ 
    var stockings = new List<Services.Models.Admin.SiteStockingLevelsModel>(); 
    IsBusy = true; 
    cts?.Cancel(); 
    cts = new CancellationTokenSource(); 
    var token = cts.Token; 
    await Task.Run(() => { CreateStockingCollection(token); }); 
    ValidateMaterials(); 
    IsBusy = false; 
} 

private void CreateStockingCollection(CancellationToken token) 
{ 
    var stockings = _siteStockingLevelsService.GetSiteInventoryLevels(SiteId, token); 
    CreateStockingLevelCompareCollection(stockings); 
    StockingLevels = 
     _mapper.Map<TrulyObservableCollection<SiteStockingLevelsModel>>(stockings);    

    ((INotifyPropertyChanged)StockingLevels).PropertyChanged += 
     (x, y) => CompareStockingChanges(); 
    CompareStockingChanges(); 
} 

在这里,我把它传递给GetSiteInventoryLevels,这听起来像这将是这项工作的长期运行的一部分。 GetSiteInventoryLevels现在必须采取CancellationToken并将其传递给它正在使用的任何API。

1

.Net中异步编程的最佳实践之一是Async all the way。看起来你的方法不是基于异步的,也不接受CancellationToken。您需要将其添加到您的方法中,换句话说,只有Task.Run将尝试取消您的任务,这样做效果不佳。

此外,CancellationTokenSource唯一的创造是不够的 - 你需要使用它在你的代码.Token财产 - 这将正是令牌:

await Task.Run(() => { CreateStockingCollection(); }, cts.Token); 
相关问题