0

As of now, the following code calls the Tick?.Invoke method every second. Is there a way to easily change the code so that it gets called every 5 seconds for example?

private void Timer()
{
    var now = DateTime.Now;
    int lastSecond = now.Second;
    int lastDay = now.Day;

    while (goOnTiming)
    {
        now = DateTime.Now;

        if (now.Second != lastSecond)
        {
            Tick?.Invoke(this, new TickEventArgs(now: now));
            lastSecond = now.Second;
        }

        if (lastDay != now.Day)
        {
                NewDay?.Invoke(this, new TickEventArgs(now: now));
                lastDay = now.Day;
        }

    }
}
Igal
  • 163
  • 1
  • 10
user2831306
  • 33
  • 1
  • 6

2 Answers2

1

You could use a builtin timer class, there are various.

You could also use my base class for an async ticker:

    /// <summary>
    /// Base class for an async ticker (runs a function every period or 'tick')
    /// Adapted from <see href="https://stackoverflow.com/a/62724908/4122889"/>
    /// NOTE this class was not designed to handle UI in any way - it could, but test beforehand!
    /// </summary>
    public abstract class TickerBase
    {
        #region Properties and Fields

        private readonly ILogger<TickerBase> _logger;
        public TimeSpan Interval { get; protected set; }

        private readonly Action<ILogger, string, Exception> _tickerStarted = LoggerMessage.Define<string>(LogLevel.Trace, new EventId(0, nameof(_tickerStarted)), "Starting ticker: {0}");
        private readonly Action<ILogger, string, Exception> _tickerCancelled = LoggerMessage.Define<string>(LogLevel.Trace, new EventId(0, nameof(_tickerCancelled)), "Cancellation requested: {0}");

        #endregion

        #region Construction and Destruction

        protected TickerBase(ILoggerFactory loggerFactory, TimeSpan interval)
        {
            if(interval == default) throw new ArgumentOutOfRangeException(nameof(interval), "Interval was its default value");

            _logger = loggerFactory.CreateLogger<TickerBase>() ?? throw new ArgumentNullException(nameof(loggerFactory));
            Interval = interval;
        }

        #endregion

        #region Starting

        /// <summary>
        /// Start the ticker. Don't await this function, it will run indefinitely.
        /// Be mindful of exceptions.
        /// Calling this function more than once will start more tasks and thus more tickers.
        /// </summary>
        /// <param name="ctx">cancellation token to cancel the timer</param>
        /// <returns></returns>
        public async Task StartAsync(CancellationToken ctx = default)
        {
            // Log starting and stopping of ticker(s)
            _tickerStarted(_logger, GetType().Name, null);
            ctx.Register(() => _tickerCancelled(_logger, GetType().Name, null));

            while (true)
            {
                var delayTask = Task.Delay(Interval, ctx);
                await OnTickAsync(ctx)
                    .ConfigureAwait(false);
                await delayTask
                    .ConfigureAwait(false);

                ctx.ThrowIfCancellationRequested();
            }

            // ReSharper disable once FunctionNeverReturns Reason: as designed
        }

        protected abstract Task OnTickAsync(CancellationToken ctx = default);
    }

    #endregion
}
sommmen
  • 6,570
  • 2
  • 30
  • 51
1

Use timers, you can use system timers or form timers. Below an example of a system timer:

    private void CreateTimer()
    {
        var timer = new System.Threading.Timer(timerCallback);
        timer.Change(0, 5000);
    }

    private void timerCallback(object state)
    {
        System.Console.WriteLine("The timer called me");
    }

BTW probably you take a lot of CPU with your approach.

Rene
  • 59
  • 3