diff --git a/src/Modern.Forms/Timer.cs b/src/Modern.Forms/Timer.cs new file mode 100644 index 0000000..e644ace --- /dev/null +++ b/src/Modern.Forms/Timer.cs @@ -0,0 +1,153 @@ +using System.ComponentModel; +using Modern.WindowKit.Threading; + +namespace Modern.Forms +{ + /// + /// Implements a timer that raises an event at user-defined intervals. + /// This timer is intended for UI-related scenarios and raises its + /// event on the UI thread. + /// + /// + /// Use this component when periodic work must be performed on the UI thread, + /// such as updating UI state, animations, or scheduling lightweight tasks. + /// + /// This timer uses internally and is therefore + /// integrated with the current UI dispatcher. + /// + public class Timer : Component + { + private DispatcherTimer? dispatcherTimer; + private int interval = 100; + private bool enabled; + private EventHandler? onTimer; + + /// + /// Initializes a new instance of the class. + /// + public Timer () + { + } + + /// + /// Occurs when the specified timer interval has elapsed and the timer is enabled. + /// + public event EventHandler Tick { + add => onTimer += value; + remove => onTimer -= value; + } + + /// + /// Gets or sets a value indicating whether the timer is running. + /// + [DefaultValue (false)] + public bool Enabled { + get => enabled; + set { + if (enabled == value) + return; + + enabled = value; + + if (enabled) + StartTimer (); + else + StopTimer (); + } + } + + /// + /// Gets or sets the time, in milliseconds, between timer ticks. + /// + /// + /// Thrown when the value is less than 1. + /// + [DefaultValue (100)] + public int Interval { + get => interval; + set { + ArgumentOutOfRangeException.ThrowIfLessThan (value, 1); + + if (interval == value) + return; + + interval = value; + + if (dispatcherTimer is not null) + dispatcherTimer.Interval = TimeSpan.FromMilliseconds (interval); + } + } + + /// + /// Starts the timer. + /// + public void Start () => Enabled = true; + + /// + /// Stops the timer. + /// + public void Stop () => Enabled = false; + + /// + /// Raises the event. + /// + /// An that contains the event data. + protected virtual void OnTick (EventArgs e) + { + onTimer?.Invoke (this, e); + } + + private void StartTimer () + { + if (dispatcherTimer is null) { + dispatcherTimer = new DispatcherTimer (); + dispatcherTimer.Tick += DispatcherTimer_Tick; + } + + dispatcherTimer.Interval = TimeSpan.FromMilliseconds (interval); + dispatcherTimer.Start (); + } + + private void StopTimer () + { + dispatcherTimer?.Stop (); + } + + private void DispatcherTimer_Tick (object? sender, EventArgs e) + { + OnTick (EventArgs.Empty); + } + + /// + /// Releases the resources used by the . + /// + /// + /// to release managed resources; otherwise, . + /// + protected override void Dispose (bool disposing) + { + if (disposing) { + enabled = false; + StopTimer (); + + if (dispatcherTimer is not null) { + dispatcherTimer.Tick -= DispatcherTimer_Tick; + dispatcherTimer = null; + } + + onTimer = null; + } + + base.Dispose (disposing); + } + + /// + /// Returns a string that represents the current timer. + /// + /// A string containing the type name and interval. + public override string ToString () + { + return $"{base.ToString ()}, Interval: {Interval}"; + } + } +}