// Copyright (c) The Perspex Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. using System; using System.Reactive.Disposables; using Perspex.Platform; namespace Perspex.Threading { /// /// A timer that uses a to fire at a specified interval. /// public class DispatcherTimer { private IDisposable _timer; private readonly DispatcherPriority _priority; private TimeSpan _interval; /// /// Initializes a new instance of the class. /// public DispatcherTimer() { _priority = DispatcherPriority.Normal; Dispatcher = Dispatcher.UIThread; } /// /// Initializes a new instance of the class. /// /// The priority to use. public DispatcherTimer(DispatcherPriority priority) { _priority = priority; Dispatcher = Dispatcher.UIThread; } /// /// Initializes a new instance of the class. /// /// The priority to use. /// The dispatcher to use. public DispatcherTimer(DispatcherPriority priority, Dispatcher dispatcher) { _priority = priority; Dispatcher = dispatcher; } /// /// Initializes a new instance of the class. /// /// The interval at which to tick. /// The priority to use. /// The dispatcher to use. /// The event to call when the timer ticks. public DispatcherTimer(TimeSpan interval, DispatcherPriority priority, EventHandler callback, Dispatcher dispatcher) { _priority = priority; Dispatcher = dispatcher; Interval = interval; Tick += callback; } /// /// Finalizes an instance of the class. /// ~DispatcherTimer() { if (_timer != null) { Stop(); } } /// /// Raised when the timer ticks. /// public event EventHandler Tick; /// /// Gets the dispatcher that the timer uses. /// public Dispatcher Dispatcher { get; } /// /// Gets or sets the interval at which the timer ticks. /// public TimeSpan Interval { get { return _interval; } set { bool enabled = IsEnabled; Stop(); _interval = value; IsEnabled = enabled; } } /// /// Gets or sets a value indicating whether the timer is running. /// public bool IsEnabled { get { return _timer != null; } set { if (IsEnabled != value) { if (value) { Start(); } else { Stop(); } } } } /// /// Gets or sets user-defined data associated with the timer. /// public object Tag { get; set; } /// /// Starts a new timer. /// /// /// The method to call on timer tick. If the method returns false, the timer will stop. /// /// The interval at which to tick. /// The priority to use. /// An used to cancel the timer. public static IDisposable Run(Func action, TimeSpan interval, DispatcherPriority priority = DispatcherPriority.Normal) { var timer = new DispatcherTimer(priority); timer.Interval = interval; timer.Tick += (s, e) => { if (!action()) { timer.Stop(); } }; timer.Start(); return Disposable.Create(() => timer.Stop()); } /// /// Starts the timer. /// public void Start() { if (!IsEnabled) { IPlatformThreadingInterface threading = PerspexLocator.Current.GetService(); _timer = threading.StartTimer(Interval, InternalTick); } } /// /// Stops the timer. /// public void Stop() { if (IsEnabled) { IPlatformThreadingInterface threading = PerspexLocator.Current.GetService(); _timer.Dispose(); _timer = null; } } /// /// Raises the event on the dispatcher thread. /// private void InternalTick() { Dispatcher.Post(RaiseTick, _priority); } /// /// Raises the event. /// private void RaiseTick() { if (Tick != null) { Tick(this, EventArgs.Empty); } } } }