|
using System; |
|
using System.Threading; |
|
using Windows.ApplicationModel; |
|
using Windows.UI.Xaml; |
|
|
|
namespace IanSavchenko.Services |
|
{ |
|
/// <summary> |
|
/// Provides real time clock events. |
|
/// </summary> |
|
public class ClockService |
|
{ |
|
private readonly object _subscriptionLock = new object(); |
|
private EventHandler<ClockTickEventArgs> _minuteEventHandler; |
|
private Timer _minuteTimer; |
|
|
|
/// <summary> |
|
/// Invoked every minute, when minute changes on a clock |
|
/// </summary> |
|
public event EventHandler<ClockTickEventArgs> MinuteTick |
|
{ |
|
add |
|
{ |
|
lock (_subscriptionLock) |
|
{ |
|
_minuteEventHandler += value; |
|
EnableMinuteTicks(); |
|
} |
|
} |
|
remove |
|
{ |
|
lock (_subscriptionLock) |
|
{ |
|
_minuteEventHandler -= value; |
|
if (_minuteEventHandler == null) |
|
DisableMinuteTicks(); |
|
} |
|
} |
|
} |
|
|
|
private void EnableMinuteTicks() |
|
{ |
|
if (_minuteTimer != null) |
|
return; |
|
|
|
InitTimer(); |
|
|
|
Application.Current.Suspending += AppOnSuspending; |
|
Application.Current.Resuming += AppOnResuming; |
|
} |
|
|
|
private void DisableMinuteTicks() |
|
{ |
|
if (_minuteTimer == null) |
|
return; |
|
|
|
_minuteTimer.Dispose(); |
|
_minuteTimer = null; |
|
|
|
Application.Current.Suspending -= AppOnSuspending; |
|
Application.Current.Resuming -= AppOnResuming; |
|
} |
|
|
|
private void InitTimer() |
|
{ |
|
_minuteTimer = new Timer(OnMinuteTick, null, TimeSpan.FromSeconds(60 - DateTime.Now.Second), TimeSpan.FromMinutes(1)); |
|
} |
|
|
|
private void OnMinuteTick(object arg) |
|
{ |
|
_minuteEventHandler?.Invoke(this, new ClockTickEventArgs(DateTime.Now, ClockTickType.Normal)); |
|
} |
|
|
|
private void AppOnSuspending(object sender, SuspendingEventArgs suspendingEventArgs) |
|
{ |
|
_minuteTimer.Change(-1, -1); |
|
_minuteTimer.Dispose(); |
|
} |
|
|
|
private void AppOnResuming(object sender, object e) |
|
{ |
|
InitTimer(); |
|
_minuteEventHandler?.Invoke(this, new ClockTickEventArgs(DateTime.Now, ClockTickType.Delayed)); |
|
} |
|
} |
|
|
|
|
|
/// <summary> |
|
/// Clock tick event payload |
|
/// </summary> |
|
public class ClockTickEventArgs |
|
{ |
|
public ClockTickEventArgs(DateTime time, ClockTickType clockTickType) |
|
{ |
|
Time = time; |
|
ClockTickType = clockTickType; |
|
} |
|
|
|
public ClockTickType ClockTickType { get; private set; } |
|
|
|
public DateTime Time { get; private set; } |
|
} |
|
|
|
|
|
/// <summary> |
|
/// Type of tick event |
|
/// </summary> |
|
public enum ClockTickType |
|
{ |
|
/// <summary> |
|
/// Event was invoked in real time or close to it |
|
/// </summary> |
|
Normal, |
|
|
|
/// <summary> |
|
/// Event was invoked with a delay, because it couldn't be invoked in real time |
|
/// </summary> |
|
Delayed, |
|
} |
|
} |