簡體   English   中英

使用CancellationToken來中斷嵌套任務

[英]Use a CancellationToken to interrupt nested tasks

這是我的場景:用戶單擊WPF按鈕,該按鈕啟動地圖上點集合的開放時段。 當用戶單擊“完成收集”按鈕時,我希望CollectPoints()任務完成。

以下是我的SegmentRecorder類:

    private CancellationTokenSource _cancellationToken;     

    public virtual async void RecordSegment(IRoadSegment segment)
    {
        _cancellationToken = new CancellationTokenSource();
        var token = _cancellationToken.Token;

        // await user clicking points on map
        await CollectPoints(token);

        // update the current segment with the collected shape.
        CurrentSegment.Shape = CurrentGeometry as Polyline;
    }

    // collect an arbitrary number of points and build a polyline.
    private async Task CollectPoints(CancellationToken token)
    {
        var points = new List<MapPoint>();
        while (!token.IsCancellationRequested)
        {
            // wait for a new point.
            var point = await CollectPoint();
            points.Add(point);

            // add point to current polyline
            var polylineBuilder = new PolylineBuilder(points, SpatialReferences.Wgs84);
            CurrentGeometry = polylineBuilder.ToGeometry();

            // draw points
            MapService.DrawPoints(CurrentGeometry);
        }
    }

    // collect a point from map click.
    protected override Task<MapPoint> CollectPoint()
    {
        var tcs = new TaskCompletionSource<MapPoint>();
        EventHandler<IMapClickedEventArgs> handler = null;
        handler = (s, e) =>
        {
            var mapPoint = e.Geometry as MapPoint;
            if (mapPoint != null)
            {
                tcs.SetResult(new MapPoint(mapPoint.X, mapPoint.Y, SpatialReferences.Wgs84));
            }
            MapService.OnMapClicked -= handler;
        };
        MapService.OnMapClicked += handler;

        return tcs.Task;
    }

    public void StopSegment(){
        // interrupt the CollectPoints task.
        _cancellationToken.Cancel();
    }

以下是我的視圖模型的相關部分:

public SegmentRecorder SegmentRecorder { get; }
public RelayCommand StopSegment { get; }

public ViewModel(){
    StopSegment = new RelayCommand(ExecuteStopSegment);
    SegmentRecorder = new SegmentRecorder();
}

// execute on cancel button click.
public void ExecuteStopSegment(){
    SegmentRecorder.StopSegment();
}

當我while (!token.IsCancellationRequested)上放置一個斷點並單擊取消按鈕時,我從未達到過這一點。

我是否以正確的方式使用取消令牌?

只要遇到while條件, CollectPoints方法就會返回!token.IsCancellationRequested在您調用CancellationTokenSourceCancel()方法后第一次返回。

里面的代碼的任務不會被取消while循環仍在執行。

正如@JSteward在他的評論中建議的那樣,你應該在你的StopSegment()方法中取消或完成TaskCompletionSource

像這樣的東西:

public virtual async void RecordSegment(IRoadSegment segment)
{
    _cancellationToken = new CancellationTokenSource();
    var token = _cancellationToken.Token;

    // await user clicking points on map
    await CollectPoints(token);

    // update the current segment with the collected shape.
    CurrentSegment.Shape = CurrentGeometry as Polyline;
}

// collect an arbitrary number of points and build a polyline.
private async Task CollectPoints(CancellationToken token)
{
    var points = new List<MapPoint>();
    while (!token.IsCancellationRequested)
    {
        try
        {
            // wait for a new point.
            var point = await CollectPoint(token);

            //...
        }
        catch (Exception) { }
    }
}

private TaskCompletionSource<MapPoint> tcs;
protected override Task<MapPoint> CollectPoint()
{
    tcs = new TaskCompletionSource<MapPoint>();
    //...
    return tcs.Task;
}

public void StopSegment()
{
    // interrupt the CollectPoints task.
    _cancellationToken.Cancel();
    tcs.SetCanceled();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM