对SystemWindowsFormsTimer的编程不能再简单了——它有一个非常简单和可直接编程的接口Start和Stop方法实际上提供了一个设置使能属性的改变方法(其本身是对Win?的SetTimer和KillTimer功能的一个包装)我刚才提到的间隔属性名字本身就说明了问题即使技术上你可以设置间隔属性低到毫秒但你应该知道在NET框架文档中指出这个属性大约精确到毫秒(假定UI线程对于处理是可用的)
捕捉由SystemWindowsFormsTimer类实例引发的事件是通过感知一个标准的EventHandler委托的标记事件来处理的就像下面的代码片断所示
System
Windows
Forms
Timer tmrWindowsFormsTimer = new System
Windows
Forms
Timer();tmrWindowsFormsTimer
Interval =
;tmrWindowsFormsTimer
Tick += new EventHandler(tmrWindowsFormsTimer_Tick);tmrWindowsFormsTimer
Start();
private void tmrWindowsFormsTimer_Tick(object sender
System
EventArgs e){ //Do something on the UI thread
}
SystemTimersTimer
NET框架文档指出SystemTimersTimer类是一个服务器定时器是为多线程环境进行设计和优化该定时器类的实例能够被多个线程安全地访问不像SystemWindowsFormsTimerSystemTimersTimer缺省的将在一个工作者线程上调用你的定时器事件处理函数该工作者线程是从公共语言运行时(CLR)线程池中获得这意味着在你的逝去的时间处理函数代码中必须遵从Win编程的黄金规则除了创建该控件实例的线程之外一个控件的实例从来不被任何其它的线程所访问
SystemTimersTimer提供了一个简单的方法处理这样的困境——暴露一个公共的SynchronizingObject属性把该属性设置为一个窗体实例(或者窗体上的一个控件)将保证你的事件处理函数代码运行在SynchronizingObject被实例化的同一个线程里
如果你使用了Visual Studio NET工具箱Visual Studio NET自动的设置SynchronizingObject属性为当前的窗体实例首先它设定该定时器的SynchronizingObject属性使其在功能上同SystemWindowsFormsTimer类一样对于大部分功能的确是这样当操作系统通知SystemTimersTimer类所允许的定时时间已过去定时器使用SynchronizingObjectBeginInvoke方法在一个线程上去执行事件委托该线程是创建SynchronizingObject的线程事件处理函数将被阻塞直到UI线程能够处理它然而不像SystemWindowsFormsTimer类一样该事件最终仍然能够被引发像你在Figure 中看到的当UI线程不能够处理时SystemWindowsFormsTimer不会引发事件可是当UI线程可用时SystemTimersTimer却会排队等候处理
Figure 是如何使用SynchronizingObject属性的例子使用例子程序并通过选择SystemTimersTimer的radio按钮你可以分析这个类并按照执行SystemWindowsFormsTimer类行为的同样顺序运行该类这样就会产生Figure 的输出结果
正如你所看到的它不会跳过一个跳动——即使UI线程在睡眠在每一个事件间隔就有一个时间消失事件处理会被排队执行因为UI线程在睡眠所以当UI线程一旦被唤醒例子程序就会列出个定时器事件(到)并能够处理处理函数
正如我早先提到的SystemTimersTimer类成员非常类似与SystemWindowsFormsTimer最大的区别就在与SystemTimersTimer类是对Win可等待定时对象的一个包装并在工作者线程上产生一个时间片消失事件而不是在UI线程上产生一个时间标记事件时间片消失事件必须与一个同ElapsedEventHandler委托像匹配的事件处理函数相连接事件处理函数接受一个ElapsedEventArgs类型的参数
除了标准的EventArgs成员ElapsedEventArgs类暴露了一个公共的SignalTime属性它包含了一个精确的定时器时间片消失的时间因为这个类支持不同线程的访问除了时间消失事件所在的线程应该相信它的Stop方法能够被其它线程所调用这会潜在的导致消失事件被引发即使其Stop方法已经被调用你可以把SignalTime和Stop方法调用的时间进行比较来解决这个问题
SystemTimersTimer也提供了AutoReset属性来决定当时间片消失事件引发后是继续进行还是只这一次要记住在定时器开始后重设间隔属性会导致当前计数为比如设置了一个秒的间隔在间隔被改变为秒时秒已经过去了那么下一个定时器事件将会在上一个定时器事件秒后发生
SystemThreadingTimer
第三个定时器类来自SystemThreading名字空间我愿意说这是所有定时器类中最好的一个但这会引起误导举一个例子我惊讶的发现对于驻留在SystemThreading名字空间的这个类天生就不是线程安全的(很明显这不意味着它不能以线程安全的方式使用)这个类的可编程接口同其它两个类也不一致它稍微有点麻烦
[] [] [] []