使用CancellationToken来中断嵌套任务

时间:2017-09-15 14:20:07

标签: c# wpf async-await

以下是我的方案:用户单击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)行上设置断点并点击取消按钮时,我从未达到过这一点。

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

1 个答案:

答案 0 :(得分:4)

CollectPoints方法会在您调用while的{​​{1}}方法后第一次遇到!token.IsCancellationRequested条件Cancel()时返回。< / p>

{/ 1>}循环中的代码仍在执行时,任务不会被取消。

正如@JSteward在评论中建议的那样,您应该取消或完成CancellationTokenSource方法中的while

这样的事情:

TaskCompletionSource