2013-08-20 104 views
3

我想要使用System.Windows.Forms.Timer来确保事件在我创建的Excel插件的UI线程上触发。我构建了计时器如下:System.Windows.Forms.Timer not firing

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);     
} 

据我了解,当我创建的加载项线程定时器,即使它是从另一个线程(COM事件在这种情况下)开始,就应该解雇的线程上,它WA s创建,即插件线程。但是,这不会发生。

我在过去编写的RTDServeras outlined by Kenny Kerr)中实现了这个确切的机制,它按预期工作,但在这种情况下_timer从不打勾。

我也读过other SO articles指向相同的行为,不知道我的插件设置有什么不同?

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

+2

是您的事件onEvent解雇了吗? – Ehsan

+0

是的,事件发生。 –

+0

你有什么异常吗? – Ehsan

回答

5

我最初打算张贴此作为评论,但它变得太长了。

首先,你的线程结构对我来说有点混乱,就像你描述的那样。将Debug.WriteLine("OnEvent:" + Thread.CurrentThread.ManagedThreadId)放在OnEvent的内部,让我们知道您从调试输出中看到的所有线程ID。

也就是说,规则是:

  • 你应该上STA thread创造的WinForms' Timer对象,并开始之前,螺纹应配置为STA。

  • 此线程可能是也可能不是主UI线程(您的主窗体创建时),但它仍应执行消息循环(使用Application.Run)来触发定时器事件。还有其他抽取消息的方法(example),但通常你不能从.NET代码中控制它。

  • 您应该在创建的同一个线程上处理由WinForms'Timer产生的事件。如果你愿意,你可以'转发'这些事件到另一个线程上下文(使用SynchronizationContextSendPost),但我想不出任何这种复杂性的原因。

@Maarten的答案实际上是在我看来提出了正确的做法。

+2

我忘记了STA线程的需求。感谢您的输入! –

2

winforms计时器是一个控件,必须将它放在窗体上使用。你永远不会将它添加到控件集合中,所以我不希望它能够正常工作。 The documentation说以下内容

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

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

请注意,上面使用的Tick-event在System.Timer.Timer类中被称为另一个名称,即Elapsed-event

+0

从Kerr文章引用System.Windows.Forms.Timer时:“内部它创建一个隐藏窗口来处理WM_TIMER消息,然后引发Tick事件。”看到这里:http://weblogs.asp.net/kennykerr/archive/2008/11/13/Rtd3.aspx –

+0

任何谁downvoted @马腾的答案做错了。这是一个概念上正确的答案,upvoting。唯一的小点,Winform'Timer'对象不必添加到表单中,但它仍然必须在STA UI线程上创建。 – Noseratio