2014-02-06 4 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

Хотя вы можете приостановить Thread, задача будет запущена, это будет даже хуже, чем Sleep(), который вы уже используете.

Вы должны заменить все это таймером WinForms. Это устраняет необходимость в Invoke() и Sleep(), и таймер можно легко остановить (Enabled = false;).

+0

Лучший ответ до сих пор, +1. OP использует фоновый поток только для обратного вызова потока пользовательского интерфейса, по-видимому, для использования цикла 'for'. Популярный анти-шаблон, вот [аналогичный случай] (http://stackoverflow.com/q/21592036/1768303). – Noseratio

0

Нет встроенной функции для этого в Task или Thread. Только планировщик ОС может приостанавливать и возобновлять поток после запуска. Но обходный может использовать CancellationToken в качестве аргумента

TaskFactory.StartNew<TResult> Method (Func<TResult>, 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

Затем, нажав кнопку, вы можете сигнализировать о том, чтобы сделать паузу. Я предполагаю, что у вас будет «непредвиденное» действие при повторном нажатии кнопки.

Для большего контроля смотрите в ManualResetEventSlimMSDN

+0

Нет, он используется для синхронизации 2 потоков и не подходит для начала возобновления. «AutoResetEvent позволяет потокам общаться друг с другом посредством сигнализации. Обычно этот класс используется, когда потоки нуждаются в эксклюзивном доступе к ресурсу». –

+0

@ K.B Да, я думал, что событие кнопки и популяция диаграммы будут обрабатываться на разных потоках, и поэтому вы можете использовать основной поток пользовательского интерфейса для управления работой любого фонового потока, выполняемого Task. Но это, вероятно, немного «круглый колышек для квадратного отверстия» для этих классов. – MattC

0

Один обходной путь будет не делая паузу нить, а с помощью Thread.Sleep на основе переменной (или свойства), который устанавливается и сбрасывается в потоке пользовательского интерфейса.

... 

     Thread.Sleep(50);//the sleep that you have in your code 
     while (paused) 
     { 
     Thread.Sleep(100); 
     } 
    ... 
Смежные вопросы