前文介紹過兩種基於 ThreadPool 的 Timer(System.Threading.Timer、System.Timers.Timer),其回調執行於非 UI 線程,操作控件必須 Invoke/BeginInvoke。第三種 System.Windows.Forms.Timer 回調直接在 UI 線程執行,無需跨線程調用。
private System.Windows.Forms.Timer timer1 = new System.Windows.Forms.Timer();
private System.Timers.Timer timer2 = new System.Timers.Timer();
public Form2()
{
InitializeComponent();
}
// Load 事件
this.Text = string.Concat("#", Thread.CurrentThread.ManagedThreadId);
// timer2.SynchronizingObject = this; // 註解掉以觀察差異
timer2.Interval = 1000;
timer2.Elapsed += new System.Timers.ElapsedEventHandler(timer2_Elapsed);
timer2.Enabled = true;
timer1.Interval = 1000;
timer1.Tick += new System.EventHandler(this.timer1_Tick);
timer1.Enabled = true;
private void timer1_Tick(object sender, EventArgs e)
{
label1.Text = string.Format("timer1 : #{0} {1} {2}",
Thread.CurrentThread.ManagedThreadId, this.InvokeRequired, DateTime.Now.ToString());
}
private void timer2_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
label2.Text = string.Format("timer2 : #{0} {1} {2}",
Thread.CurrentThread.ManagedThreadId, this.InvokeRequired, DateTime.Now.ToString());
}

結果證明:Forms.Timer 回調在 UI 線程(InvokeRequired=False),Timers.Timer 回調在 ThreadPool 線程(InvokeRequired=True)。若將 timer2.SynchronizingObject = this 取消註解,Timers.Timer 也會封送至 UI 線程。