2

我想做的事。我想 SomeMethod 将被定期调用。因此,我想在后台线程方法主体通过后从后台线程启动计时器。_timer.Start()被调用,但 TickHandler 没有;

代码:

using Timer = System.Windows.Forms.Timer;

class TestTimer
    {
        private Timer _timer;
        private Thread _thread;

        public TestTimer()
        {
            // create and initializing timer. but not started!
            _timer = new Timer();
            _timer.Tick += TickHandler;
            _timer.Interval = 60000; // 1 minute

            // create and start new thread
            _thread = new Thread(SomeMethod);
            _thread.Start();
        }

        private void TickHandler(object sender, EventArgs e)
        {
            // stop timer
            _timer.stop();

            //some handling

            // run background thread again
            _thread = new Thread(SomeMethod);
            _thread.Start();
        }   

        private void SomeMethod()
        {
            // some operations

            // start timer!
            TimerStart();
        }

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

通过猴子方法,我发现如果像这样添加代表

internal delegate void TimerDelegate();

并替换字符串

TimerStart(); 

Application.Current.Dispatcher.Invoke(new TimerDelegate(TimerStart), null);

一切正常。有人可以解释我的诀窍是什么吗?

4

2 回答 2

4

你把事情搞混了。

如果您想要一个在后台线程上触发的计时器,您不必创建一个线程来启动它(哪个线程调用该方法并不重要)。只需使用,每个事件都将发生在线程池线程上。StartSystem.Timers.TimerElapsed

如果您想要一个在UI 线程上触发的计时器,因为看起来您正在使用 WPF,您应该使用,而不是您一直在使用的 Windows 窗体计时器。您应该在特定的 UI 线程上创建计时器(即 call ),并且每个事件都将在该线程上发生。同样,从哪个线程调用也没关系。System.Windows.Threading.DispatcherTimernewTickStart

以下是对代码中发生的情况的解释:您正在非 UI 线程上启动 Windows 窗体计时器。这种计时器需要在该线程上运行消息泵,以便它可以接收消息。因为它是一个非 UI 线程,所以没有消息泵。当您使用该Dispatcher.Invoke方法时,您将计时器的创建编组回应用程序的主 UI 线程,使其工作。但这一切都是多余的。如果您想保持代码不变,只需将计时器替换为DispatcherTimer,然后您就可以删除Invoke调用。

或者,如果您使用的是 .NET 4.5,您可以使用 await/async 使这一切变得更容易(确保SomeMethod从 UI 线程调用):

async Task SomeMethod(CancellationToken ct)
{
    while (!ct.IsCancellationRequested)
    {
        await Task.Run(() => DoAsyncStuff(), ct);

        DoUIStuff();

        await Task.Delay(TimeSpan.FromMinutes(1), ct);
    }
}
于 2013-10-01T06:24:23.333 回答
0

MSDN可以为你解释:

注意 Windows 窗体计时器组件是单线程的,精度限制为 55 毫秒。如果您需要更准确的多线程计时器,请使用 System.Timers 命名空间中的 Timer 类。

于 2013-10-01T06:27:58.380 回答