How System.Timers.Timer behave in WPF application, after Hibernate, and Sleep?

后端 未结 4 793
说谎
说谎 2020-12-29 22:43

I\'m using System.Timers.Timer in my WPF application. I want to understand how Timer does behave, after Computer is hibernated, and sleep. I\'m getting some

4条回答
  •  梦谈多话
    2020-12-29 23:21

    An simple alarm class accepting an absolute Utc time that will survive a sleep cycle. The alarm can then be adjusted from the alarm callback to go off again. No periodic mode is supported to keep it simple. Based strongly on the answer from @PeterDuniho. Full disclosure: minimally tested.

    using Microsoft.Win32;
    using System;
    using System.Threading;
    
    class AlarmSleepTolerant : IDisposable
    {
        readonly Timer _timer;
        DateTime? _alarmUtcOpt;
    
        /// 
        /// Constructor
        /// 
        /// 
        /// 
        /// 
        public AlarmSleepTolerant(TimerCallback callback, DateTime? alarmUtcOpt = null, object stateOpt = null) 
        {
            SystemEvents.PowerModeChanged += _OnPowerModeChanged;
            _timer = new Timer(callback, stateOpt, Timeout.Infinite, Timeout.Infinite);
            SetAlarmTime(alarmUtcOpt);
        }
        
        /// 
        /// Set the current alarm, if alarmUtc is <= UtcNow, then the alarm goes off immediately.
        /// Pass null to disable the alarm.
        /// 
        /// 
        public void SetAlarmTime(DateTime? alarmUtcOpt = null)
        {
            lock (_timer)
            {
                _alarmUtcOpt = alarmUtcOpt;
    
                if (!alarmUtcOpt.HasValue)
                {
                    _timer.Change(Timeout.Infinite, Timeout.Infinite); // disables the timer
                }
                else
                {
                    TimeSpan dueIn = _alarmUtcOpt.Value - DateTime.UtcNow;
                    _timer.Change(dueIn.Ticks <= 0 ? 0 : (long)dueIn.TotalMilliseconds, Timeout.Infinite);
                }
            }
        }
    
        public void Dispose()
        {
            SystemEvents.PowerModeChanged -= _OnPowerModeChanged;
            _timer.Dispose();
        }
    
        void _OnPowerModeChanged(object sender, PowerModeChangedEventArgs e)
        {
            // Timers are based on intervals rather than absolute times so they 
            // need to be adjusted upon a resume from sleep.
            // 
            // If the alarm callback was missed during sleep, it will be called now.
            //
            if (e.Mode == PowerModes.Resume)
            {
                lock (_timer)
                    SetAlarmTime(_alarmUtcOpt);
            }
        }    
    }
    

提交回复
热议问题