System.Windows.Forms.Timer not firing

本文关键字:not firing Timer Forms Windows System | 更新日期: 2023-09-27 18:28:21

我想使用System.Windows.Forms.Timer来确保在我正在创建的excel加载项的UI线程上触发事件。我构造计时器如下:

private System.Windows.Forms.Timer _timer;
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
    Debug.WriteLine("ThisAddIn_Startup:" + Thread.CurrentThread.ManagedThreadId);
    _timer = new System.Windows.Forms.Timer();
    _timer.Tick += new EventHandler(TimerEventHandler);
    _timer.Interval = 500;            
}

计时器由我正在使用的库中的COM事件触发:

private void OnEvent()
{
    _timer.Start();
}

然后,我希望_timer在勾选时调用以下方法:

public void TimerEventHandler(object sender, EventArgs args)
{
    _timer.Stop();
    Debug.WriteLine("Tick: " + Thread.CurrentThread.ManagedThreadId);                  
}

据我所知,当我在Addin线程中创建计时器时,即使它是从另一个线程启动的(本例中为COM事件),它也应该在创建它的线程上启动,即Addin线程。然而,这并没有发生。

我已经在我过去写的RTDServer中实现了这个确切的机制(正如Kenny Kerr所概述的),它如预期的那样工作,但在这种情况下,_timer永远不会成功。

我也读过其他SO文章,这些文章指出了相同的行为,但我不知道我的插件设置有什么不同?

编辑:OnEvent()方法被激发。

System.Windows.Forms.Timer not firing

winforms计时器是一个控件,必须将其放置在窗体上才能使用。您从未将其添加到控件集合中,因此我不希望它正常工作。文件显示以下

实现以用户定义的时间间隔引发事件的计时器此计时器已针对Windows窗体应用程序进行了优化,必须在窗口中使用

因此,我建议您使用System.Timers.Timer类的实例。这个类可以在任何地方使用。

请注意,上面使用的Tick事件由System.Timer.Timer类中的另一个名称调用,即Elapsed事件。

我最初想把它作为评论发布,但它太长了。

首先,你描述的线程结构让我有点困惑。把Debug.WriteLine("OnEvent:" + Thread.CurrentThread.ManagedThreadId)放在OnEvent中,让我们知道你从调试输出中看到的所有线程ID。

也就是说,规则是:

  • 您应该在STA线程上创建WinForms的Timer对象,并且该线程在启动之前应该配置为STA。

  • 这个线程可能是也可能不是主UI线程(创建主窗体的地方),但它仍然应该执行一个消息循环(使用Application.Run),以便触发计时器事件。还有其他方法可以泵送消息,但通常您不能从.NET代码中控制它们。

  • 您应该在创建WinForms的Timer的同一线程上处理其来源的事件。然后,如果您愿意,您可以将这些事件"转发"到另一个线程上下文(使用SynchronizationContext SendPost),但我想不出有任何原因导致这种复杂性。

在我看来,@Maarten的回答实际上表明了正确的做法。

我还不明白为什么Forms.Timer没有按预期运行,但下面这篇优秀的文章详细解释了如何将工作封送到UI线程上:http://www.codeproject.com/Articles/31971/Understanding-SynchronizationContext-Part-I