Самый простой способ выполнять метод периодически – использовать таймер, например класс Timer из пространства имен System.Threading. Этот таймер использует пул потоков, допуская создание множества таймеров без накладных расходов в виде такого же количества потоков. Timer – довольно простой класс с конструктором и парой методов (просто наслаждение для минималистов и авторов книг!).
public sealed class Timer: MarshalByRefObject, IDisposable { public Timer(TimerCallback tick, object state, 1st, subsequent); public bool Change(1st, subsequent); // Для изменения периода public void Dispose(); // Для удаления } // 1st = время до первого срабатывания в миллисекундах или как TimeSpan // subsequent = следующие интервалы в миллисекундах или как TimeSpan // (используйте Timeout.Infinite для одноразового срабатывания) |
В следующем примере таймер вызывает метод Tick, который печатает "tick..." по истечении 5 секунд и далее каждую секунду, пока пользователь не нажмет Enter:
using System; using System.Threading; class Program { static void Main() { Timer tmr = new Timer(Tick, "tick...", 5000, 1000); Console.ReadLine(); tmr.Dispose(); // Остановка таймера } static void Tick(object data) { // Этот код выполняется на потоке из пула Console.WriteLine(data); // Печать: "tick..." } } |
.NET Framework предоставляет также другой класс таймера с тем же самым именем в пространстве имен System.Timers. Это простая обертка System.Threading.Timer, с тем же самым основным механизмом, обеспечивающая дополнительные удобства при использовании пула потоков. Вот основные дополнительные возможности:
|
|
§ Реализация в виде компонента, позволяющая размещать его в дизайнере Visual Studio.
§ Свойство Interval вместо метода Change.
§ Событие Elapsed вместо делегата обратного вызова.
§ Свойство Enabled для запуска и остановки таймера (значение по умолчанию – false).
§ Методы Start и Stop на случай, если вам не нравится Enabled.
§ Флаг AutoReset для указания необходимости периодических срабатываний (значение по умолчанию – true).
Вот пример:
using System; using System.Timers; // Пространство имен Timers вместо Threading class SystemTimer { static void Main() { Timer tmr = new Timer(); // Конструктор без параметров tmr.Interval = 500; tmr.Elapsed += tmr_Elapsed; // Событие вместо делегата tmr.Start(); // Запустить таймер Console.ReadLine(); tmr.Stop(); // Остановить таймер Console.ReadLine(); tmr.Start(); // Продолжить Console.ReadLine(); tmr.Dispose(); // Остановить навсегда } static void tmr_Elapsed(object sender, EventArgs e) { Console.WriteLine("Tick"); } } |
.NET Framework предоставляет еще и третий вид таймера – в пространстве имен System.Windows.Forms. Похожий на System.Timers.Timer по интерфейсу, он радикально отличается от него по функциональности. Таймер Windows Forms не использует пула потоков, вместо этого вызывая событие “Tick” всегда в том же самом потоке, в котором был создан таймер. При условии, что таймер создается в главном потоке, там же, где все формы и элементы управления приложения Windows Forms, обработчик события срабатывания таймера может взаимодействовать с формой и элементами управления без нарушения потоковой безопасности и необходимости вызовов Control.Invoke.
|
|
Таймер Windows Forms предназначен для заданий, которые могут привести к обновлению пользовательского интерфейса, и которые должны выполняться достаточно быстро. Быстрота выполнения важна, так как событие Tick вызывается в главном потоке, а значит, во время его выполнения интерфейс не будет отвечать на действия пользователя.