2014-02-06 3 views
1

나는 MS 차트 컨트롤이 있습니다. 별도의 스레드를 만들어 포인트를 채우고 각 포인트를 플로팅 한 다음 스레드를 잠자기 상태로 둔 다음 다음 포인트를 플롯하여 그래프가 움직이는 것처럼 보이게 만듭니다. 다음은 코드입니다.이벤트가 생성 될 때 작업 일시 중지

Task[] t = new Task[1]; 
t[0] = Task.Factory.StartNew(() => plotChartPoints()); 



    public void plotPoint(int x, double y, int series) 
    { 
     comparisonChart.Series[series].Points.AddXY(x, y); 
    } 

    public void refreshChart() 
    { 
     this.mainSplitContainer.Panel2.Refresh(); 
    } 

    public void plotChartPoints() 
    { 
     //comparisonChart.Series[0].Points.DataBindXY(xValuesSeries1.ToArray(), yValuesSeries1.ToArray()); 
     //comparisonChart.Series[1].Points.DataBindXY(xValuesSeries2.ToArray(), yValuesSeries2.ToArray()); 
     for (int index = 0; index < xValuesSeries1.Count; index++) 
     { 
      if (comparisonChart.InvokeRequired) 
      { 
       comparisonChart.Invoke(new MethodInvoker(() => plotPoint(xValuesSeries1.ElementAt(index), yValuesSeries1.ElementAt(index), 0))); 
       comparisonChart.Invoke(new MethodInvoker(() => plotPoint(xValuesSeries2.ElementAt(index), yValuesSeries2.ElementAt(index), 1))); 
      } 
      Thread.Sleep(50); 
      if (this.mainSplitContainer.InvokeRequired) 
      { 
       mainSplitContainer.Invoke(new MethodInvoker(()=> refreshChart())); 
      } 

     } 
    } 

지금, 나는 버튼을 추가 할 버튼이 차트 일시 정지 및 차트 정지를 채우고 작업을 클릭하면되도록. 어떻게해야합니까? .NET 4.0을 사용 중이며 Task 클래스의 작업을 일시 중지 할 수있는 방법이 없습니다.

+0

작은 쿼리. '채울 수있는 별도의 스레드를 만듭니다'라고 말하면서, 새로운'Task'가 항상 새로운 스레드를 생성 할 수 있다고는 확신 할 수 없습니다. – MattC

+0

VS2012 + 및 ['Microsoft.Bcl.Async'] (http://www.nuget.org/packages/microsoft.bcl.async)를 사용할 수 있습니까? – Noseratio

답변

2

이미 작업하고있는 스레드를 일시 중지 할 수 있지만 이미 사용중인 Sleep()보다 나빠질 수 있습니다.

이 모든 것을 WinForms 타이머로 바꾸어야합니다. 이렇게하면 Invoke() 및 Sleep()이 필요없고 타이머를 쉽게 중지 할 수 있습니다 (Enabled = false;).

+0

지금까지 가장 좋은 대답은 +1입니다. OP는 UI 스레드를 콜백하기 위해서만 배경 스레드를 사용하고 있으며, 'for' 루프를 사용할 수있는 것 같습니다. 인기있는 안티 패턴은 다음과 같습니다 [유사한 경우] (http://stackoverflow.com/q/21592036/1768303). – Noseratio

0

작업 또는 스레드에서만 수행 할 수있는 기본 제공 기능이 없습니다. OS 스케줄러는 일단 시작되면 스레드를 일시 중지했다가 다시 시작할 수 있습니다. 그러나 작품은 주위 버튼을 클릭 한 후 인수

TaskFactory.StartNew<TResult> Method (Func<TResult>, CancellationToken) 

로 CancellationToken을 사용하는 방법 및 범위 변수의 아웃 인덱스의 현재 값을 저장하고 당신이 클릭 할 때에서 색인을 시작할 수 있습니다 재개 할 수 있습니다 당신이 그것을 할 수있는 방법을 간단한 예 다음에 도달 할 점은

/// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     private ChartController _chartController = new ChartController(); 
     public bool paused; 

     public MainWindow() 
     { 
      InitializeComponent(); 

     } 

     private void PlayPauseButton_OnClick(object sender, RoutedEventArgs e) 
     { 
      paused = !paused; 
      if (!paused) 
      { 
       _chartController.CancelAnim(); 
      } 
      else 
      _chartController.StartTask(); 
     } 
    } 

    public class ChartController 

    { 
     private CancellationTokenSource tokenSource = new CancellationTokenSource(); 
     private CancellationToken _cancellationToken; 

     private int reachedChartIndex = 0; 
     public void CancelAnim() 
     { 
      tokenSource.Cancel(); 
     } 
     public ChartController() 
     { 

     } 

     public void StartTask() 
     { 
      Task t = Task.Factory.StartNew(() => plotChartPoints(), tokenSource.Token); 
      _cancellationToken = tokenSource.Token; 


      //to handle exeption if there is 
      try 
      { 
       t.Wait(); 
      } 
      catch (AggregateException e) 
      { 
       foreach (var v in e.InnerExceptions) 
       //here manage task exception 
      } 
     } 



     public void plotPoint(int x, double y, int series) 
     { 
      comparisonChart.Series[series].Points.AddXY(x, y); 
     } 

     public void refreshChart() 
     { 
      this.mainSplitContainer.Panel2.Refresh(); 
     } 

     public void plotChartPoints() 
     { 

      _cancellationToken.ThrowIfCancellationRequested(); 

      //comparisonChart.Series[0].Points.DataBindXY(xValuesSeries1.ToArray(), yValuesSeries1.ToArray()); 
      //comparisonChart.Series[1].Points.DataBindXY(xValuesSeries2.ToArray(), yValuesSeries2.ToArray()); 
      for (int index = reachedChartIndex; index < xValuesSeries1.Count; index++) 
      { 
       if (_cancellationToken.IsCancellationRequested) 
       { 
        reachedChartIndex = index; 
        break; 
       } 
       if (comparisonChart.InvokeRequired) 
       { 
        comparisonChart.Invoke(
         new MethodInvoker(
          () => plotPoint(xValuesSeries1.ElementAt(index), yValuesSeries1.ElementAt(index), 0))); 
        comparisonChart.Invoke(
         new MethodInvoker(
          () => plotPoint(xValuesSeries2.ElementAt(index), yValuesSeries2.ElementAt(index), 1))); 
       } 
       Thread.Sleep(50); 
       if (this.mainSplitContainer.InvokeRequired) 
       { 
        mainSplitContainer.Invoke(new MethodInvoker(() => refreshChart())); 
       } 

      } 
     } 

    } 

} 
0

당신은 아마도 AutoResetEventMSDN

사용할 수

버튼을 클릭하면 플로팅 신호를 보내 일시 중지 신호를 보낼 수 있습니다. 버튼을 다시 클릭하면 '일시 중지 해제'작업을 수행한다고 가정합니다. 이상의 제어 옵션

설정되는 실을 일시 정지하지 않지만 가변 (또는 특성)에 기초하여에 Thread.sleep하여 오히려 수와 UI 스레드에 의해 리셋 것이다 ManualResetEventSlim MSDN

+0

아니요 두 스레드를 동기화하는 데 사용되며 시작 재개에 적합하지 않습니다 "AutoResetEvent는 스레드가 신호로 서로 통신 할 수있게 해줍니다. 일반적으로 스레드가 리소스에 단독 액세스해야하는 경우이 클래스를 사용합니다." –

+0

@ K.B 그래, 제 생각에 버튼 이벤트와 차트 채우기가 다른 스레드에서 처리 될 것이므로 주 UI 스레드를 사용하여 작업이 실행되고 있던 백그라운드 스레드의 작업을 제어 할 수있었습니다. 하지만 아마도이 클래스의 '사각형 구멍 용 둥근 나무못'일 것입니다. – MattC

0

한 대안으로 보인다.

... 

     Thread.Sleep(50);//the sleep that you have in your code 
     while (paused) 
     { 
     Thread.Sleep(100); 
     } 
    ... 
관련 문제