2017-09-15 2 views
3

내 시나리오는 다음과 같습니다. 사용자가지도상의 점 집합에 대한 개방 기간을 시작하는 WPF 버튼을 클릭합니다. 사용자가 "수집 완료"버튼을 클릭하면 CollectPoints() 작업을 완료하고 싶습니다. 여기 CancellationToken을 사용하여 중첩 된 작업을 중단하십시오.

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

내보기 모델의 관련 부분은 다음과 같습니다 :

가 여기 내 SegmentRecorder 클래스의 조각입니다

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 조건 !token.IsCancellationRequested 당신이 CancellationTokenSourceCancel() 방법을 호출 한 후 처음으로 안타 때마다

+2

측면 참고 : 이벤트 핸들러가 아닌 방법에 대한'비동기 void'을 사용할 수 없습니다. – dymanoid

+0

당신은'CollectPoint' 내부에서 취소를 처리 할 필요가있을 것입니다, 그것은 아마도 그것이 지금 기다리고있는 곳일 것입니다. – JSteward

+2

사용자가 포인트 수집을 중지하면 CollectPoint 태스크가 완료 될 때까지 적어도 하나 이상의 포인트를 수집해야합니다.이 태스크는 'while'실행을 일시 중지합니다. 'CollectPoint' 외부의'tcs '를 잡고 완료하거나 취소 할 때 취소하면 예상대로 완료됩니다. – JSteward

답변

4

CollectPoints 방법은 반환합니다.

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

내 솔루션은 이것과 매우 유사했다. 단지 새'Task'를 만들고 내 토큰을'CollectPoint'에 전달했다.'var point = Task.Run (CollectPoint (token), token);을 기다린다. – wdonahoe