2010-09-29 3 views
2

У меня есть программа оконных форм с формой MainForm. При нажатии кнопки я запускаю код, который запускается (импульсы) на каждые 0,5 секунды в другом потоке. Я хочу изменить многие вещи, такие как метки, progressbars на моем MainForm, из метода Pulse. Как это возможно? Так что я хотел бы знать, как вставлять переменные, значения в этот поток и MainForm. Изменяйте друг друга и т. Д.Как передать значения между потоками?

Нажав кнопку foo, я говорю, что я начинаю пульсатор. Pulsator.Initialize();

Вот класс Pulsator:

public static class Pulsator 
{ 
    private static Thread _worker; 

    public static void Initialize() 
    { 
     _worker = new Thread(Pulse); 
     _worker.IsBackground = true; 
     _worker.Start(); 
    } 

    public static void Close() 
    { 
     if (_worker != null) 
     { 
      _worker.Abort(); 
      while (_worker.IsAlive || _worker.ThreadState != ThreadState.Stopped) 
      { 
       //closing 
      } 
     } 
    } 

    public static void Pulse() 
    { 
     if (_worker != null) 
     { 
      while (true) 
      { 
       SomeOtherClass.Pulse(); 
       Thread.Sleep(500); 
      } 
     } 
     else 
     { 
      SomeOtherClass.Pulse(); // yeah I know this doesnt needed 
     } 
    } 
} 

SomeOtherClass Импульсный метод выглядит следующим образом:

public static void Pulse() 
    { 
     //here I will have several values, variables, and I want to show results, 
     // values on my MainForm, like: 
     Random random = new Random(); 
     MainForm.label1.Text = random.Next(123,321).ToString(); // I hope you know what I mean 
    } 

Конечно, это очень сложно, это просто глупый пример.

+0

Также имейте в виду, что вызов Thread.Abort вызывает исключение ThreadAbortException, которое вам необходимо обслуживать в методе Close, http://msdn.microsoft.com/en-us/library/system.threading.thread.abort. aspx – w69rdy

ответ

1

Как и другие уже упоминалось, вы должны использовать Control.Invoke изменить элементы управления пользовательского интерфейса от фонового потока.

Другой вариант - использовать System.ComponentModel.BackgroundWorker (он доступен в панели инструментов конструктора форм). Затем вы можете использовать таймер обычной формы, чтобы вызвать RunWorkerAsync-Method и выполнить фоновое задание в обработчике событий DoWork, который автоматически вызывается из другого потока.

Оттуда вы можете передать данные обратно в основной поток, вызвав ReportProgress. Это приведет к событию ProgressChanged в основном потоке, где вы можете обновить все элементы управления пользовательским интерфейсом.

4

Как правило, в WinForms небезопасно изменять состояние визуальных элементов управления вне потока, которому принадлежат неуправляемые ресурсы управления (дескриптор окна). Вы должны использовать метод Control.Invoke, чтобы запланировать выполнение изменений в потоке управления.

0

C# 2 или выше (VS2005) имеет анонимных делегатов (и C# 3 имеет lambdas, которые являются немного более опрятной версией той же идеи).

Они позволяют начать поток с помощью функции, которая может «видеть» переменные в окружающем пространстве. Поэтому нет необходимости явно передавать ему что-либо. С другой стороны, существует опасность того, что поток случайно будет зависеть от того, что он не должен (например, переменная, которая изменяется в других потоках).

_worker = new Thread(delegate 
{ 
    // can refer to variables in enclosing scope(s). 
}); 
1

Почему бы не использовать System.Timers.Timer?

т.д .:

 trainPassageTimer = new Timer(500); 
     trainPassageTimer.AutoReset = true; 
     trainPassageTimer.Elapsed += TimeElapsed; 

     ... 

     private void TimeElapsed(object sender, ElapsedEventArgs elapsedEventArgs) 
     { 
// Do stuff 
// Remember to use BeginInvoke or Invoke to access Windows.Forms controls 
     } 
+0

System.Windows.Forms.Timer будет лучшим выбором для работы с пользовательским интерфейсом: http://msdn.microsoft.com/msdnmag/issues/04/02/TimersinNET/default.aspx – lesscode

Смежные вопросы