浏览代码

Merge pull request #1196 from kekekeks/timer-priority

Fixed DispatcherTimer's priorities
Nikita Tsukanov 8 年之前
父节点
当前提交
a06631f1a9

+ 1 - 1
src/Android/Avalonia.Android/AndroidThreadingInterface.cs

@@ -30,7 +30,7 @@ namespace Avalonia.Android
             return;
         }
 
-        public IDisposable StartTimer(TimeSpan interval, Action tick)
+        public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick)
         {
             if (interval.TotalMilliseconds < 10)
                 interval = TimeSpan.FromMilliseconds(10);

+ 2 - 1
src/Avalonia.Base/Platform/IPlatformThreadingInterface.cs

@@ -17,10 +17,11 @@ namespace Avalonia.Platform
         /// <summary>
         /// Starts a timer.
         /// </summary>
+        /// <param name="priority"></param>
         /// <param name="interval">The interval.</param>
         /// <param name="tick">The action to call on each tick.</param>
         /// <returns>An <see cref="IDisposable"/> used to stop the timer.</returns>
-        IDisposable StartTimer(TimeSpan interval, Action tick);
+        IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick);
 
         void Signal(DispatcherPriority priority);
 

+ 13 - 0
src/Avalonia.Base/Threading/Dispatcher.cs

@@ -84,6 +84,19 @@ namespace Avalonia.Threading
             _jobRunner?.Post(action, priority);
         }
 
+        /// <summary>
+        /// This is needed for platform backends that don't have internal priority system (e. g. win32)
+        /// To ensure that there are no jobs with higher priority
+        /// </summary>
+        /// <param name="currentPriority"></param>
+        internal void EnsurePriority(DispatcherPriority currentPriority)
+        {
+            if (currentPriority == DispatcherPriority.MaxValue)
+                return;
+            currentPriority += 1;
+            _jobRunner.RunJobs(currentPriority);
+        }
+
         /// <summary>
         /// Allows unit tests to change the platform threading interface.
         /// </summary>

+ 4 - 14
src/Avalonia.Base/Threading/DispatcherTimer.cs

@@ -17,13 +17,11 @@ namespace Avalonia.Threading
         private readonly DispatcherPriority _priority;
 
         private TimeSpan _interval;
-
-        private readonly Action _raiseTickAction;
-
+        
         /// <summary>
         /// Initializes a new instance of the <see cref="DispatcherTimer"/> class.
         /// </summary>
-        public DispatcherTimer() : this(DispatcherPriority.Normal)
+        public DispatcherTimer() : this(DispatcherPriority.Background)
         {
         }
 
@@ -34,7 +32,6 @@ namespace Avalonia.Threading
         public DispatcherTimer(DispatcherPriority priority)
         {
             _priority = priority;
-            _raiseTickAction = RaiseTick;
         }
 
         /// <summary>
@@ -187,7 +184,7 @@ namespace Avalonia.Threading
                     throw new Exception("Could not start timer: IPlatformThreadingInterface is not registered.");
                 }
 
-                _timer = threading.StartTimer(Interval, InternalTick);
+                _timer = threading.StartTimer(_priority, Interval, InternalTick);
             }
         }
 
@@ -210,14 +207,7 @@ namespace Avalonia.Threading
         /// </summary>
         private void InternalTick()
         {
-            Dispatcher.UIThread.InvokeAsync(_raiseTickAction, _priority);
-        }
-
-        /// <summary>
-        /// Raises the <see cref="Tick"/> event.
-        /// </summary>
-        private void RaiseTick()
-        {
+            Dispatcher.UIThread.EnsurePriority(_priority);
             Tick?.Invoke(this, EventArgs.Empty);
         }
     }

+ 2 - 4
src/Gtk/Avalonia.Gtk3/Gtk3Platform.cs

@@ -70,15 +70,13 @@ namespace Avalonia.Gtk3
                 Native.GtkMainIteration();
         }
 
-        public IDisposable StartTimer(TimeSpan interval, Action tick)
+        public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick)
         {
             var msec = interval.TotalMilliseconds;
-            if (msec <= 0)
-                throw new ArgumentException("Don't know how to create a timer with zero or negative interval");
             var imsec = (uint) msec;
             if (imsec == 0)
                 imsec = 1;
-            return GlibTimeout.StarTimer(imsec, tick);
+            return GlibTimeout.StartTimer(GlibPriority.FromDispatcherPriority(priority), imsec, tick);
         }
 
         private bool[] _signaled = new bool[(int) DispatcherPriority.MaxValue + 1];

+ 2 - 4
src/Gtk/Avalonia.Gtk3/Interop/GlibTimeout.cs

@@ -48,12 +48,10 @@ namespace Avalonia.Gtk3.Interop
             }
         }
 
-        public static IDisposable StarTimer(uint interval, Action tick)
+        public static IDisposable StartTimer(int priority, uint interval, Action tick)
         {
-            if (interval == 0)
-                throw new ArgumentException("Don't know how to create a timer with zero or negative interval");
             var timer = new Timer ();
-            GlibTimeout.Add(GlibPriority.FromDispatcherPriority(DispatcherPriority.Normal), interval,
+            GlibTimeout.Add(priority, interval,
                 () =>
                 {
                     if (timer.Stopped)

+ 2 - 2
src/Linux/Avalonia.LinuxFramebuffer/PlatformThreadingInterface.cs

@@ -17,7 +17,7 @@ namespace Avalonia.LinuxFramebuffer
         public PlatformThreadingInterface()
         {
             TlsCurrentThreadIsLoopThread = true;
-            StartTimer(new TimeSpan(0, 0, 0, 0, 66), () => Tick?.Invoke(this, new EventArgs()));
+            StartTimer(DispatcherPriority.Render, new TimeSpan(0, 0, 0, 0, 66), () => Tick?.Invoke(this, new EventArgs()));
         }
 
         private readonly AutoResetEvent _signaled = new AutoResetEvent(false);
@@ -74,7 +74,7 @@ namespace Avalonia.LinuxFramebuffer
             }
         }
 
-        public IDisposable StartTimer(TimeSpan interval, Action tick)
+        public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick)
         {
             return new WatTimer(new System.Threading.Timer(delegate
             {

+ 1 - 1
src/OSX/Avalonia.MonoMac/PlatformThreadingInterface.cs

@@ -16,7 +16,7 @@ namespace Avalonia.MonoMac
 
         public event Action<DispatcherPriority?> Signaled;
 
-        public IDisposable StartTimer(TimeSpan interval, Action tick)
+        public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick)
             => NSTimer.CreateRepeatingScheduledTimer(interval, () => tick());
 
         public void Signal(DispatcherPriority prio)

+ 1 - 1
src/Windows/Avalonia.Win32/Win32Platform.cs

@@ -114,7 +114,7 @@ namespace Avalonia.Win32
             }
         }
 
-        public IDisposable StartTimer(TimeSpan interval, Action callback)
+        public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action callback)
         {
             UnmanagedMethods.TimerProc timerDelegate =
                 (hWnd, uMsg, nIDEvent, dwTime) => callback();

+ 1 - 1
src/iOS/Avalonia.iOS/PlatformThreadingInterface.cs

@@ -51,7 +51,7 @@ namespace Avalonia.iOS
             }
         }*/
 
-        public IDisposable StartTimer(TimeSpan interval, Action tick)
+        public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick)
             => NSTimer.CreateRepeatingScheduledTimer(interval, _ => tick());
 
         public void Signal(DispatcherPriority prio)

+ 1 - 1
tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Threading.cs

@@ -160,7 +160,7 @@ namespace Avalonia.Base.UnitTests
                 throw new NotImplementedException();
             }
 
-            public IDisposable StartTimer(TimeSpan interval, Action tick)
+            public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick)
             {
                 throw new NotImplementedException();
             }

+ 1 - 1
tests/Avalonia.RenderTests/TestBase.cs

@@ -161,7 +161,7 @@ namespace Avalonia.Direct2D1.RenderTests
                 throw new NotImplementedException();
             }
 
-            public IDisposable StartTimer(TimeSpan interval, Action tick)
+            public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick)
             {
                 throw new NotImplementedException();
             }