C# 定时器不工作';我不想在它被禁用后重新启动

C# 定时器不工作';我不想在它被禁用后重新启动,c#,multithreading,timer,C#,Multithreading,Timer,我正在编写一个简单的C#程序,它尝试使用System.Forms.Timer每隔x秒执行一次操作 tick事件调用一个方法,该方法启动一个新线程并禁用计时器,然后当该线程完成其工作时,它会再次启用计时器,但问题是,现在它在启用后不会滴答作响 static System.Windows.Forms.Timer testtimer = new System.Windows.Forms.Timer(); static void Main() { testtimer.T

我正在编写一个简单的C#程序,它尝试使用System.Forms.Timer每隔x秒执行一次操作

tick事件调用一个方法,该方法启动一个新线程并禁用计时器,然后当该线程完成其工作时,它会再次启用计时器,但问题是,现在它在启用后不会滴答作响

static System.Windows.Forms.Timer testtimer = new System.Windows.Forms.Timer();

    static void Main()
    {
        testtimer.Tick += testtimertick;
        testtimer.Interval = 5000;
        testtimer.Enabled = true;
        testtimer.Start();

        while (true)
        {
            Application.DoEvents();  //Prevents application from exiting
        }

    }

 private static void testtimertick(object sender, System.EventArgs e)
    { 

            testtimer.Enabled = false;
            Thread t = new Thread(dostuff);
            t.Start();
    }


private static void dostuff()
    {

       //Executes some code
       testtimer.Enabled = true; //Re enables the timer but it doesn't work
       testtimer.Start();
     }

Windows窗体控件不是线程安全的,您应该确保在UI线程上使用它们,例如,请参见不要在没有GUI的情况下使用GUI计时器。不要使用
DoEvents
旋转,因为这样会消耗100%的CPU内核。使用
系统.Threading.Timer
。它可以正常工作。

您可以使用来做您想做的事情,使用来设置时间和时段,完成工作后重新启动即可

static System.Windows.Forms.Timer testtimer = new System.Windows.Forms.Timer();

    static void Main()
    {
        testtimer.Tick += testtimertick;
        testtimer.Interval = 5000;
        testtimer.Enabled = true;

        while (true)
        {
            Application.DoEvents();  //Prevents application from exiting
        }

    }

 private static void testtimertick(object sender, System.EventArgs e)
    { 

            Thread t = new Thread(dostuff);
            t.Start();
    }


private static void dostuff()
    {
       testtimer.Enabled = false;
       //Executes some code
       testtimer.Enabled = true; //Re enables the timer but it doesn't work
       testtimer.Start();
     }
class Program
{
    static System.Threading.Timer testtimer;
    static void Main(string[] args)
    {
        testtimer = new System.Threading.Timer(testtimertick);
        testtimer.Change(5000,0);

        Console.ReadLine();
    }

    private static void testtimertick(object sender)
    {

        Thread t = new Thread(dostuff);
        t.Start();
    }


    private static void dostuff()
    {

        //Executes some code
        Thread.Sleep(2000);
        Console.WriteLine("Tick");
        testtimer.Change(5000, 0);
    }
}
,您的问题似乎与以下事实有关:您正在对在不同线程上创建的Windows窗体控件进行跨线程调用

如果您使用的是.NET4.5(C#5.0),我建议您查看,可以在

关于如何使用async和Wait处理遗留“DoStuff”的示例:

注意事项:

  • 异步已添加到计时器勾号事件的签名中
  • wait关键字和Task.Run用于异步运行DoStuff

  • 当使用这些关键字时,DoStuff将异步运行,一旦DoStuff返回,它将使用最初调用Tick的线程的上下文在wait之后继续运行

    我刚才也有类似的问题。我正在禁用计时器,并在需要时再次启用。 下次启用时,它将不起作用

    当我想禁用计时器对象时,我试着处理它,并在每次我想启用它时创建它的新实例。但是没用

    然后想出了一个解决办法。我正在删除testtimer.Tick中配置的事件,然后在需要启用计时器时将其添加回

    因此,计时器内部将始终使用有效值实例化,并使其属性Enabled=true。唯一的区别是,每当触发勾号事件时,它实际上不会执行任何操作


    这将模拟禁用和启用计时器,并使其与您控制的一样工作,如Enabled=false/true。

    如果您真的想坚持使用GUI计时器,并从非UI线程启动它,您可以尝试执行类似的操作,然后从非UI线程写入GUI

    我知道这不是理想的解决办法

    this.Invoke((MethodInvoker)delegate
    {
        refreshTimer.Enabled = true;
        refreshTimer.Start();
    });
    

    只是为了确认你在这里的意图;您希望计时器触发,然后在
    dostuff()
    方法完成之前不触发?是的,确切地说,计时器不应该在dostuff未完成时启动。您是否尝试过
    timer.Stop()
    ,然后在其准备就绪时再尝试
    timer.start()
    ?我也不太确定计时器是否是线程安全类,所以请检查testTimer.Enabled=true;相当于testTimer.start();请看:我假设您指的是我没有使用线程计时器的事实……我只是坚持OPs实现,尽管我同意使用线程计时器更好,但我认为您希望将0更改为
    Timeout.Infinite
    。即
    testtimer.Change(5000,Timeout.Infinite)参见@JimMischel实际上根据文档,它们都做相同的事情。如果period为零(0)或无穷大,且dueTime不是无穷大,则回调方法调用一次;计时器的周期行为已禁用,但可以通过调用Change并为period from指定正值来重新启用
    
    this.Invoke((MethodInvoker)delegate
    {
        refreshTimer.Enabled = true;
        refreshTimer.Start();
    });