.NET, event every minute (on the minute). Is a timer the best option?

后端 未结 14 2092
-上瘾入骨i
-上瘾入骨i 2020-11-27 03:02

I want to do stuff every minute on the minute (by the clock) in a windows forms app using c#. I\'m just wondering whats the best way to go about it ?

I could use a t

相关标签:
14条回答
  • 2020-11-27 03:34

    I jsut wrote this class using the WPF DispatcherTimer but you can swap the dispatcher for any timer that supports changing when it's woken from sleep state.

    The class is constructed with a fixed time step and supprts Start/Stop/Reset, Start/Stop/Start works like a resume operation. The timer is like a stopwatch in that regard.

    A clock implementation would simply create the class with a interval of 1 second and listen to the event. Be wary though that this is a real-time clock, if the tick event takes longer than the interval to finish you'll notice that the clock will try and catch up to real-time this will cause a burst of tick events being raised.

    public class FixedStepDispatcherTimer
    {
        /// <summary>
        /// Occurs when the timer interval has elapsed.
        /// </summary>
        public event EventHandler Tick;
    
        DispatcherTimer timer;
    
        public bool IsRunning { get { return timer.IsEnabled; } }
    
        long step, nextTick, n;
    
        public TimeSpan Elapsed { get { return new TimeSpan(n * step); } }
    
        public FixedStepDispatcherTimer(TimeSpan interval)
        {
            if (interval < TimeSpan.Zero)
            {
                throw new ArgumentOutOfRangeException("interval");
            }
            this.timer = new DispatcherTimer();
            this.timer.Tick += new EventHandler(OnTimerTick);
            this.step = interval.Ticks;
        }
    
        TimeSpan GetTimerInterval()
        {
            var interval = nextTick - DateTime.Now.Ticks;
            if (interval > 0)
            {
                return new TimeSpan(interval);
            }
            return TimeSpan.Zero; // yield
        }
    
        void OnTimerTick(object sender, EventArgs e)
        {
            if (DateTime.Now.Ticks >= nextTick)
            {
                n++;
                if (Tick != null)
                {
                    Tick(this, EventArgs.Empty);
                }
                nextTick += step;
            }
            var interval = GetTimerInterval();
            Trace.WriteLine(interval);
            timer.Interval = interval;
        }
    
        public void Reset()
        {
            n = 0;
            nextTick = 0;
        }
    
        public void Start()
        {
            var now = DateTime.Now.Ticks;
            nextTick = now + (step - (nextTick % step));
            timer.Interval = GetTimerInterval();
            timer.Start();
        }
    
        public void Stop()
        {
            timer.Stop();
            nextTick = DateTime.Now.Ticks % step;
        }
    }
    
    0 讨论(0)
  • 2020-11-27 03:36

    Create a method or put this code where you want the timer to start:

     int time = 60 - DateTime.Now.Second; // Gets seconds to next minute
            refreshTimer.Interval = time * 1000;
            refreshTimer.Start();
    

    And then on your tick event set the interval to 60000:

      private void refreshTimer_Tick(object sender, EventArgs e)
        {
            refreshTimer.Interval = 60000; // Sets interval to 60 seconds
            // Insert Refresh logic
        }
    
    0 讨论(0)
  • 2020-11-27 03:37

    You can nail this with reactive extensions which will take care of lots of timer related problems for you (clock changes, app hibernation etc). Use Nuget package Rx-Main and code like this:

    Action work = () => Console.WriteLine(DateTime.Now.ToLongTimeString());
    
    Scheduler.Default.Schedule(
        // start in so many seconds
        TimeSpan.FromSeconds(60 - DateTime.Now.Second), 
        // then run every minute
        () => Scheduler.Default.SchedulePeriodic(TimeSpan.FromMinutes(1), work));               
    
    Console.WriteLine("Press return.");
    Console.ReadLine();
    

    Read here (search for "Introducing ISchedulerPeriodic") to see all the issues this is taking care of: http://blogs.msdn.com/b/rxteam/archive/2012/06/20/reactive-extensions-v2-0-release-candidate-available-now.aspx

    0 讨论(0)
  • 2020-11-27 03:40

    Alternatively, you could sleep to pause execution until it times out which should be close to your desired time. This will only wake the computer when the sleep finishes so it'll save you CPU time and let the CPU power down between processing events.

    This has the advantage of modifying the timeout so that it will not drift.

    int timeout = 0;
    
    while (true)  {
      timeout = (60 - DateTime.Now.Seconds) * 1000 - DateTime.Now.Millisecond;
      Thread.Sleep(timeout);
    
      // do your stuff here
    }
    
    0 讨论(0)
  • 2020-11-27 03:40

    What I'm using for scheduled tasks is a System.Threading.Timer(System.Threading.TimerCallback, object, int, int) with the callback set to the code I want to execute based on the interval which is supplied in milliseconds for the period value.

    0 讨论(0)
  • 2020-11-27 03:42

    By making use of ReactiveExtensions you could use the following code if you were interested in doing something as simple as printing to the console.

    using System;
    using System.Reactive.Linq;
    namespace ConsoleApplicationExample
    {
        class Program
        {
            static void Main()
            {
                Observable.Interval(TimeSpan.FromMinutes(1))
                .Subscribe(_ =>
                {                   
                    Console.WriteLine(DateTime.Now.ToString());
                });
                Console.WriteLine(DateTime.Now.ToString()); 
                Console.ReadLine();
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题