1

I am using System.Timers.Timer Class and I want to change it's Interval in the elapsed function. When i set Elapsed property to different value, somehow elapsed function starts firing and firing again althrough timer's Autoreset property is set to false.

my code:

            var timer = new Timer()
            {
                Interval = 1000,
                AutoReset = false,
            };

            timer.Enabled = true;
        
            timer.Elapsed += (sender, eventArgs) =>
            {
                Console.WriteLine("Timer fires");
                timer.Interval = 2000;
            };

The code results in firing timer again and again when i just wanted to change interval for the latter use of the timer.

It would be nice to know why this happens and what should i do to achieve desired behaviour.

Miamy
  • 2,162
  • 3
  • 15
  • 32
Rezga
  • 390
  • 1
  • 10
  • This is by design: [MSDN](https://learn.microsoft.com/en-us/dotnet/api/system.timers.timer.interval?view=netcore-3.1) : _If the interval is set after the Timer has started, the count is reset. For example, if you set the interval to 5 seconds and then set the Enabled property to true, the count starts at the time Enabled is set. If you reset the interval to 10 seconds when count is 3 seconds, the Elapsed event is raised for the first time 13 seconds after Enabled was set to true._ - You could try to workaround with a 2nd timer.. – TaW Jul 08 '20 at 13:46

2 Answers2

2

Timer.Close will release all resources attached with this timer object and it seems to help here.

In the Elapsed event handler logic, when the Timer.Interval is set to a number greater than zero, it's telling to invoke the "Elapsed" event again and the whole logic goes into a infinite loop.

static void Main(string[] args)
{
    var timer = new Timer()
    {
        Interval = 1000,
        AutoReset = false,
    };

    timer.Enabled = true;
    timer.Elapsed += (sender, eventArgs) =>
    {
        Console.WriteLine("Timer fires Elapsed = " + timer.Interval.ToString());
        timer.Close();
        timer.Interval = 800;
    };
    Console.WriteLine("The timer event should have fired just once. Press the Enter key to resume ");
    Console.ReadLine();

    // Again enable the timer to make sure it fires the elapsed event after 800 ms
    timer.Enabled = true;
    Console.WriteLine("Press the Enter key to resume ");
    Console.ReadLine();

    // Overwrite the earlier time interval to 200 ms.
    timer.Interval = 200;
    timer.Enabled = true;
    Console.WriteLine("Press the Enter key to resume ");
    Console.ReadLine();
            
    timer.Enabled = true;
    Console.WriteLine("Press the Enter key to exit the program at any time... ");
    Console.ReadLine();
}
1

I don't know why the Timer starts again after you change the Interval but here is a Workaround for this problem.

timer.Elapsed += (sender, eventArgs) =>
{
    Console.WriteLine("Timer fires");
    timer = new Timer()
    {
        Interval = 2000,
        AutoReset = false,
    };
};

You could also use the DispatcherTimer instead.

var dt = new DispatcherTimer();

dt.Interval = new TimeSpan(0, 0, 1);

dt.Tick += (sender, eventArgs) =>
{
    dt.Stop();
    dt.Interval = new TimeSpan(0, 0, 2);
};

Edit: After some testing, I have found a better workaround.

If you start the timer again than change the Interval and immediately afterward stop it again then it seems to work.

timer.Elapsed += (sender, eventArgs) =>
{
    Console.WriteLine("Timer fires");
    timer.Enabled = true;
    timer.Interval = 2000;
    timer.Enabled = false;
};
  • Thanks for your answer. I was thinking about using the first option here, but I don't want to create new object every time the `Elapsed` event is fired. As for the second approach, I specifically want to use `System.Timers.Timer` Due to the fact that it uses it's own thread pool and runs asynchronously. – Rezga Jul 08 '20 at 13:18
  • Yeah, I also don't think that this is a good solution. But maybe my new third approach works better for you. – Wolfram Wisser Jul 08 '20 at 13:54