// 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 object _lock = new(); protected Task? UpdateTask { get; set; } protected CancellationTokenSource? UpdateTokenSource { get; set; } protected CancellationToken UpdateToken { get; set; } 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) { if (autostart) Start(); } #endregion #region Methods /// /// Starts the trigger if needed, causing it to performing updates. /// public void Start() { lock (_lock) { 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 void Stop() { lock (_lock) { if (UpdateTask != null) { UpdateTokenSource?.Cancel(); // ReSharper disable once MethodSupportsCancellation UpdateTask.Wait(); UpdateTask.Dispose(); UpdateTask = null; } } } private void UpdateLoop() { OnStartup(); while (!UpdateToken.IsCancellationRequested) { long preUpdateTicks = Stopwatch.GetTimestamp(); OnUpdate(); if (UpdateFrequency > 0) { double lastUpdateTime = ((Stopwatch.GetTimestamp() - preUpdateTicks) / 10000.0); LastUpdateTime = lastUpdateTime; int sleep = (int)((UpdateFrequency * 1000.0) - lastUpdateTime); if (sleep > 0) Thread.Sleep(sleep); } } } /// public override void Dispose() => Stop(); #endregion } }