From 81973c881fc8bb285a65d1bf78722948dc5d7d34 Mon Sep 17 00:00:00 2001 From: Kiko kiko Date: Wed, 1 Apr 2026 19:53:59 +0200 Subject: [PATCH 1/3] Add Timer component --- src/Modern.Forms/Timer.cs | 164 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 src/Modern.Forms/Timer.cs diff --git a/src/Modern.Forms/Timer.cs b/src/Modern.Forms/Timer.cs new file mode 100644 index 0000000..cd20114 --- /dev/null +++ b/src/Modern.Forms/Timer.cs @@ -0,0 +1,164 @@ +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. + /// + [DefaultProperty (nameof (Interval))] + [DefaultEvent (nameof (Tick))] + [ToolboxItemFilter ("Modern.Forms")] + 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 () + { + } + + /// + /// Initializes a new instance of the class with the specified container. + /// + /// The container to add this component to. + public Timer (IContainer container) + : this () + { + container?.Add (this); + } + + /// + /// 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 () + { + dispatcherTimer ??= new DispatcherTimer (); + + dispatcherTimer.Interval = TimeSpan.FromMilliseconds (interval); + dispatcherTimer.Tick -= DispatcherTimer_Tick; + dispatcherTimer.Tick += DispatcherTimer_Tick; + 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) { + 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}"; + } + } +} From e2da1cf1f869e61fb0feb4265a0807ee2fa93c2b Mon Sep 17 00:00:00 2001 From: ProGraMajster <51681610+ProGraMajster@users.noreply.github.com> Date: Wed, 1 Apr 2026 23:57:46 +0200 Subject: [PATCH 2/3] Apply review feedback --- src/Modern.Forms/Timer.cs | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/src/Modern.Forms/Timer.cs b/src/Modern.Forms/Timer.cs index cd20114..9f5a1ba 100644 --- a/src/Modern.Forms/Timer.cs +++ b/src/Modern.Forms/Timer.cs @@ -15,9 +15,6 @@ namespace Modern.Forms /// This timer uses internally and is therefore /// integrated with the current UI dispatcher. /// - [DefaultProperty (nameof (Interval))] - [DefaultEvent (nameof (Tick))] - [ToolboxItemFilter ("Modern.Forms")] public class Timer : Component { private DispatcherTimer? dispatcherTimer; @@ -32,16 +29,6 @@ public Timer () { } - /// - /// Initializes a new instance of the class with the specified container. - /// - /// The container to add this component to. - public Timer (IContainer container) - : this () - { - container?.Add (this); - } - /// /// Occurs when the specified timer interval has elapsed and the timer is enabled. /// @@ -112,11 +99,12 @@ protected virtual void OnTick (EventArgs e) private void StartTimer () { - dispatcherTimer ??= new DispatcherTimer (); - + if (dispatcherTimer is null) + { + dispatcherTimer = new DispatcherTimer (); + dispatcherTimer.Tick += DispatcherTimer_Tick; + } dispatcherTimer.Interval = TimeSpan.FromMilliseconds (interval); - dispatcherTimer.Tick -= DispatcherTimer_Tick; - dispatcherTimer.Tick += DispatcherTimer_Tick; dispatcherTimer.Start (); } @@ -139,6 +127,7 @@ private void DispatcherTimer_Tick (object? sender, EventArgs e) protected override void Dispose (bool disposing) { if (disposing) { + enabled = false; StopTimer (); if (dispatcherTimer is not null) { From f2718ddfcbc5587406d8811a9166e86206c477b1 Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Wed, 1 Apr 2026 12:24:49 -1000 Subject: [PATCH 3/3] Fix formatting. --- src/Modern.Forms/Timer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Modern.Forms/Timer.cs b/src/Modern.Forms/Timer.cs index 9f5a1ba..e644ace 100644 --- a/src/Modern.Forms/Timer.cs +++ b/src/Modern.Forms/Timer.cs @@ -99,11 +99,11 @@ protected virtual void OnTick (EventArgs e) private void StartTimer () { - if (dispatcherTimer is null) - { + if (dispatcherTimer is null) { dispatcherTimer = new DispatcherTimer (); dispatcherTimer.Tick += DispatcherTimer_Tick; } + dispatcherTimer.Interval = TimeSpan.FromMilliseconds (interval); dispatcherTimer.Start (); }