2017-07-29 3 views
-1

Ich muss async Task Abbrechen implementieren. Ich weiß, dass CancellationTokenSource mir dabei helfen würde. Aber ich finde keinen richtigen Weg.Abbrechen der vorherigen Async-Aufgabe mit CancellationTokenSource

Ich habe eine Suche Textbox, wann immer ein Benutzer in Textfeld für jede Textchanged-Ereignis I GetStocks Methode aufrufen, wie unten gezeigt,

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; 
} 

Die CreateStockingCollection Verfahren wird, wie unten gezeigt,

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

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

Meine Anforderung hier ist
Beispiel Angenommen, Benutzer möchte "Abc" eingeben. Wenn der Benutzer "A" eingibt, wird die GetStocks Methode aufgerufen, der Benutzer gibt sofort "b" ein und die Methoden "get stocks" wird erneut aufgerufen. In diesem Fall möchte ich die vorherige GetStocks Aufgabe mit dem Buchstaben "A" abbrechen.

+1

FYI: eine bessere Passform dafür könnte "reaktive Erweiterungen" sein. Das Erstellen von Aufgaben basierend auf Textänderungen kann massiv verbessert werden, indem zum Beispiel die Suche nur gestartet wird, wenn mindestens 2 Zeichen vorhanden sind und wenn der Suchtext für 200ms nicht geändert wurde. Dies reduziert die kostenintensiven Anrufe. Ein Beispiel finden Sie hier: https://stackoverflow.com/questions/22873541/search-on-text-change-with-reactive-extensions. –

+2

@PeterBons hat einen ausgezeichneten Punkt, aber außerdem verwenden Sie den Token nicht irgendwo in dem Code, den Sie gepostet haben. Sie müssen das CTS-Token an alle Aufgaben übergeben, die an einer kooperativen Stornierung teilnehmen sollen. Dann sollte die Aufgabe prüfen, ob das Token besagt, dass die Operation abgebrochen werden sollte. Für nicht CPU-gebundene Operationen ist dies nicht wirklich möglich, es sei denn, das Token kann vollständig durchgelassen werden (normalerweise, indem alle Aufrufe asynchron mit Unterstützung für Stornotoken sind). Auf diese Weise können Sie beispielsweise eine Datenbankabfrage mit langer Laufzeit abbrechen. –

+0

Dies ist eine WPF-Anwendung. – Vinay

Antwort

1

Stornierung ist kooperativ, so dass Sie Sie müssen geben sie es an Ihrem eigenen Code und haben es auf diesem Token antworten:

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(); 
} 

Hier ist es zu GetSiteInventoryLevels ich vorbei, die so klingt, dass die lang andauernde Teil dieser Arbeit sein würde. GetSiteInventoryLevels muss jetzt die CancellationToken übernehmen und sie an die APIs weitergeben, die sie verwendet.

1

Eine der besten Praktiken der asynchronen Programmierung in .Net ist Async all the way. Es sieht so aus, als ob Ihre Methode nicht asyncbasiert ist. Sie akzeptiert auch keine CancellationToken. Sie müssen es zu Ihrer Methode hinzufügen, sonst wird nur Task.Run versuchen, Ihre Aufgabe abzubrechen, die nicht gut funktionieren würde.

Auch die einzige Schöpfung der CancellationTokenSource ist nicht genug - Sie brauchen .Token Eigenschaft es ist in Ihrem Code zu verwenden - das wäre genau das Token:

await Task.Run(() => { CreateStockingCollection(); }, cts.Token); 
Verwandte Themen