// 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);
}
}
}
}