长话短说,我需要 .Net 中的一个精确计时器 - 精度以毫秒为单位 - 这意味着,如果我告诉它在 10 毫秒过去时触发一个事件,它必须这样做,+-1 毫秒。内置的 .Net Timer 类的精度似乎为 +-16ms,这对于我的应用程序来说是不可接受的。
我找到了这篇文章http://www.codeproject.com/Articles/98346/Microsecond-and-Millisecond-NET-Timer http://www.codeproject.com/Articles/98346/Microsecond-and-Millisecond-NET-Timer它提供了一个计时器代码,这正是我所需要的(甚至更多 - 精度以微秒为单位)。
然而,问题是,OnTimer 等效项似乎是在另一个线程中执行的。所以,如果我添加一些代码,那么:
label1.Text = "Hello World";
我会得到一个异常,因此我实际上必须这样写:
Invoke( new MethodInvoker(() =>{label1.Text = "Hello World";}));
据我了解,这是因为 OnTimer 事件是从计时器的线程中触发的 - 时间经过,直到足够的时间超过 Interval,然后触发下一个 OnTimer 事件。 .Net Timer没有这样的问题——在.Net Timer的OnTimer中,我可以自由修改控件的成员。
问题:我应该更改什么才能让我的计时器在主线程中运行它的 OnTimer 事件?添加“Invoke”是唯一的选择吗?
虽然有多种方法可以实现这一点,但我通常更喜欢的一种方法是让计时器捕获SynchronizationContext.Current
当它被创建时。当在 UI 线程中时,该值将包含当前同步上下文,可用于在 UI 上下文中执行消息循环中的方法。这适用于 winform、WPF、silverlight 等。所有这些范例都设置同步上下文。
只需在创建计时器时获取该值(假设它是在 UI 线程中创建的)。如果您希望有一个可选的构造函数/属性来设置该值,以便即使未在 UI 线程中创建计时器也可以使用它,但大多数情况下不需要这样做。
然后只需使用Send
该上下文的方法来触发事件:
public class Timer
{
private SynchronizationContext syncContext;
public Timer()
{
syncContext = SynchronizationContext.Current;
}
public event EventHandler Tick;
private void OnTick()
{
syncContext.Send(state =>
{
if (Tick != null)
Tick(this, EventArgs.Empty);
}, null);
}
//TODO other stuff to actually fire the tick event
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)