// ----------------------------------------------------------------------- // // Copyright 2013 MIT Licence. See licence.md for more information. // // ----------------------------------------------------------------------- namespace Perspex.Threading { using System; using System.Reactive.Disposables; using Perspex.Platform; using Splat; /// /// A timer that uses a to fire at a specified interval. /// public class DispatcherTimer { private IDisposable timer; private DispatcherPriority priority; private TimeSpan interval; /// /// Initializes a new instance of the class. /// public DispatcherTimer() { this.priority = DispatcherPriority.Normal; this.Dispatcher = Dispatcher.UIThread; } /// /// Initializes a new instance of the class. /// /// The priority to use. public DispatcherTimer(DispatcherPriority priority) { this.priority = priority; this.Dispatcher = Dispatcher.UIThread; } /// /// Initializes a new instance of the class. /// /// The priority to use. /// The dispatcher to use. public DispatcherTimer(DispatcherPriority priority, Dispatcher dispatcher) { this.priority = priority; this.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) { this.priority = priority; this.Dispatcher = dispatcher; this.Interval = interval; this.Tick += callback; } /// /// Finalizes an instance of the class. /// ~DispatcherTimer() { if (this.timer != null) { this.Stop(); } } /// /// Raised when the timer ticks. /// public event EventHandler Tick; /// /// Gets the dispatcher that the timer uses. /// public Dispatcher Dispatcher { get; private set; } /// /// Gets or sets the interval at which the timer ticks. /// public TimeSpan Interval { get { return this.interval; } set { bool enabled = this.IsEnabled; this.Stop(); this.interval = value; this.IsEnabled = enabled; } } /// /// Gets or sets a value indicating whether the timer is running. /// public bool IsEnabled { get { return this.timer != null; } set { if (this.IsEnabled != value) { if (value) { this.Start(); } else { this.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 (!this.IsEnabled) { IPlatformThreadingInterface threading = Locator.Current.GetService(); this.timer = threading.StartTimer(this.Interval, this.InternalTick); } } /// /// Stops the timer. /// public void Stop() { if (this.IsEnabled) { IPlatformThreadingInterface threading = Locator.Current.GetService(); this.timer.Dispose(); this.timer = null; } } /// /// Raises the event on the dispatcher thread. /// private void InternalTick() { this.Dispatcher.InvokeAsync(this.RaiseTick, this.priority); } /// /// Raises the event. /// private void RaiseTick() { if (this.Tick != null) { this.Tick(this, EventArgs.Empty); } } } }