Here is my scenario: The user clicks a WPF button which initiates an open-ended period for the collection of points on a map. When the user clicks the "finished collecting" button, I want the CollectPoints() task to complete.
Here are pieces of my SegmentRecorder class:
    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();
    }
Here are the relevant parts of my view model:
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();
}
When I put a breakpoint on the line while (!token.IsCancellationRequested) and click the cancel button, I never get to that point.
Am I using the cancellation token in the correct way here?
 
    