System.Windows.Forms.Timer没有触发

Pat*_*ard 3 c# com multithreading timer excel-addins

我想使用a 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;            
}
Run Code Online (Sandbox Code Playgroud)

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

private void OnEvent()
{
    _timer.Start();
}
Run Code Online (Sandbox Code Playgroud)

然后我希望_timer在它滴答时调用以下方法:

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

据我所知,当我在Addin线程中创建计时器时,即使它是从另一个线程启动的(在这种情况下是COM事件),它应该触发它创建的线程,即插件线程.但是,这不会发生.

我已经在RTDServer我过去写过的这个确切的机制中实现了(正如Kenny Kerr所概述的那样)并且它按预期工作,但_timer在这种情况下从未打过.

我还阅读了其他SO文章指出相同的行为,无法弄清楚我的插件设置有什么不同?

编辑: 触发OnEvent()方法.

Maa*_*ten 6

winforms 计时器是一个控件,必须通过将其放置在窗体上来使用。你永远不会将它添加到控制集合中,所以我不希望它正常工作。该文档说以下内容

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

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

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


nos*_*tio 5

我最初的意思是发布这个评论,但它变得太长了.

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

也就是说,规则是:

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

  • 此线程可能是也可能不是主UI线程(创建主表单的位置),但仍应执行消息循环(使用Application.Run)以触发计时器事件.还有其他抽取消息的方法(例子),但通常你不会从.NET代码控制它.

  • 您应该在WinForms' Timer创建的同一个线程上处理由WinForms' 提供的事件.然后,如果您愿意,可以将这些事件"转发"到另一个线程上下文(使用SynchronizationContext SendPost),但我无法想到这种复杂性的任何原因.

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

  • 我忘记了对STA Thread的要求.感谢您的输入! (2认同)