// ReSharper disable MemberCanBePrivate.Global using System.Diagnostics; using System.Threading; using System.Threading.Tasks; namespace RGB.NET.Core { /// /// /// Represents an /// public class TimerUpdateTrigger : AbstractUpdateTrigger { #region Properties & Fields private CancellationTokenSource _updateTokenSource; private CancellationToken _updateToken; private Task _updateTask; private Stopwatch _sleepCounter; private double _updateFrequency = 1.0 / 30.0; /// /// Gets or sets the update-frequency in seconds. (Calculate by using '1.0 / updates per second') /// public double UpdateFrequency { get => _updateFrequency; set => SetProperty(ref _updateFrequency, value); } /// /// Gets the time it took the last update-loop cycle to run. /// public double LastUpdateTime { get; private set; } #endregion #region Constructors /// /// Initializes a new instance of the class. /// /// A value indicating if the trigger should automatically right after construction. public TimerUpdateTrigger(bool autostart = true) { _sleepCounter = new Stopwatch(); if (autostart) Start(); } #endregion #region Methods /// /// Starts the trigger if needed, causing it to performing updates. /// public void Start() { if (_updateTask == null) { _updateTokenSource?.Dispose(); _updateTokenSource = new CancellationTokenSource(); _updateTask = Task.Factory.StartNew(UpdateLoop, (_updateToken = _updateTokenSource.Token), TaskCreationOptions.LongRunning, TaskScheduler.Default); } } /// /// Stops the trigger if running, causing it to stop performing updates. /// public async void Stop() { if (_updateTask != null) { _updateTokenSource.Cancel(); await _updateTask; _updateTask.Dispose(); _updateTask = null; } } private void UpdateLoop() { while (!_updateToken.IsCancellationRequested) { _sleepCounter.Restart(); OnUpdate(); _sleepCounter.Stop(); LastUpdateTime = _sleepCounter.Elapsed.TotalSeconds; int sleep = (int)((UpdateFrequency * 1000.0) - _sleepCounter.ElapsedMilliseconds); if (sleep > 0) Thread.Sleep(sleep); } } #endregion } }