DispatcherTimer.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // Copyright (c) The Perspex Project. All rights reserved.
  2. // Licensed under the MIT license. See licence.md file in the project root for full license information.
  3. using System;
  4. using System.Reactive.Disposables;
  5. using Perspex.Platform;
  6. namespace Perspex.Threading
  7. {
  8. /// <summary>
  9. /// A timer that uses a <see cref="Dispatcher"/> to fire at a specified interval.
  10. /// </summary>
  11. public class DispatcherTimer
  12. {
  13. private IDisposable _timer;
  14. private readonly DispatcherPriority _priority;
  15. private TimeSpan _interval;
  16. /// <summary>
  17. /// Initializes a new instance of the <see cref="DispatcherTimer"/> class.
  18. /// </summary>
  19. public DispatcherTimer()
  20. {
  21. _priority = DispatcherPriority.Normal;
  22. }
  23. /// <summary>
  24. /// Initializes a new instance of the <see cref="DispatcherTimer"/> class.
  25. /// </summary>
  26. /// <param name="priority">The priority to use.</param>
  27. /// <param name="dispatcher">The dispatcher to use.</param>
  28. public DispatcherTimer(DispatcherPriority priority)
  29. {
  30. _priority = priority;
  31. }
  32. /// <summary>
  33. /// Initializes a new instance of the <see cref="DispatcherTimer"/> class.
  34. /// </summary>
  35. /// <param name="interval">The interval at which to tick.</param>
  36. /// <param name="priority">The priority to use.</param>
  37. /// <param name="dispatcher">The dispatcher to use.</param>
  38. /// <param name="callback">The event to call when the timer ticks.</param>
  39. public DispatcherTimer(TimeSpan interval, DispatcherPriority priority, EventHandler callback)
  40. {
  41. _priority = priority;
  42. Interval = interval;
  43. Tick += callback;
  44. }
  45. /// <summary>
  46. /// Finalizes an instance of the <see cref="DispatcherTimer"/> class.
  47. /// </summary>
  48. ~DispatcherTimer()
  49. {
  50. if (_timer != null)
  51. {
  52. Stop();
  53. }
  54. }
  55. /// <summary>
  56. /// Raised when the timer ticks.
  57. /// </summary>
  58. public event EventHandler Tick;
  59. /// <summary>
  60. /// Gets or sets the interval at which the timer ticks.
  61. /// </summary>
  62. public TimeSpan Interval
  63. {
  64. get
  65. {
  66. return _interval;
  67. }
  68. set
  69. {
  70. bool enabled = IsEnabled;
  71. Stop();
  72. _interval = value;
  73. IsEnabled = enabled;
  74. }
  75. }
  76. /// <summary>
  77. /// Gets or sets a value indicating whether the timer is running.
  78. /// </summary>
  79. public bool IsEnabled
  80. {
  81. get
  82. {
  83. return _timer != null;
  84. }
  85. set
  86. {
  87. if (IsEnabled != value)
  88. {
  89. if (value)
  90. {
  91. Start();
  92. }
  93. else
  94. {
  95. Stop();
  96. }
  97. }
  98. }
  99. }
  100. /// <summary>
  101. /// Gets or sets user-defined data associated with the timer.
  102. /// </summary>
  103. public object Tag
  104. {
  105. get;
  106. set;
  107. }
  108. /// <summary>
  109. /// Starts a new timer.
  110. /// </summary>
  111. /// <param name="action">
  112. /// The method to call on timer tick. If the method returns false, the timer will stop.
  113. /// </param>
  114. /// <param name="interval">The interval at which to tick.</param>
  115. /// <param name="priority">The priority to use.</param>
  116. /// <returns>An <see cref="IDisposable"/> used to cancel the timer.</returns>
  117. public static IDisposable Run(Func<bool> action, TimeSpan interval, DispatcherPriority priority = DispatcherPriority.Normal)
  118. {
  119. var timer = new DispatcherTimer(priority);
  120. timer.Interval = interval;
  121. timer.Tick += (s, e) =>
  122. {
  123. if (!action())
  124. {
  125. timer.Stop();
  126. }
  127. };
  128. timer.Start();
  129. return Disposable.Create(() => timer.Stop());
  130. }
  131. /// <summary>
  132. /// Starts the timer.
  133. /// </summary>
  134. public void Start()
  135. {
  136. if (!IsEnabled)
  137. {
  138. IPlatformThreadingInterface threading = PerspexLocator.Current.GetService<IPlatformThreadingInterface>();
  139. _timer = threading.StartTimer(Interval, InternalTick);
  140. }
  141. }
  142. /// <summary>
  143. /// Stops the timer.
  144. /// </summary>
  145. public void Stop()
  146. {
  147. if (IsEnabled)
  148. {
  149. IPlatformThreadingInterface threading = PerspexLocator.Current.GetService<IPlatformThreadingInterface>();
  150. _timer.Dispose();
  151. _timer = null;
  152. }
  153. }
  154. /// <summary>
  155. /// Raises the <see cref="Tick"/> event on the dispatcher thread.
  156. /// </summary>
  157. private void InternalTick()
  158. {
  159. Dispatcher.UIThread.Post(RaiseTick, _priority);
  160. }
  161. /// <summary>
  162. /// Raises the <see cref="Tick"/> event.
  163. /// </summary>
  164. private void RaiseTick()
  165. {
  166. if (Tick != null)
  167. {
  168. Tick(this, EventArgs.Empty);
  169. }
  170. }
  171. }
  172. }