Browse Source

Reverted Dispatcher.UIThread and added SingleThreadDispatcher

Nikita Tsukanov 10 years ago
parent
commit
f50a2c361c

+ 1 - 1
src/Perspex.Application/Application.cs

@@ -144,7 +144,7 @@ namespace Perspex
         {
             var source = new CancellationTokenSource();
             closable.Closed += (s, e) => source.Cancel();
-            Dispatcher.MainLoop(source.Token);
+            Dispatcher.UIThread.MainLoop(source.Token);
         }
 
         /// <summary>

+ 1 - 0
src/Perspex.Base/Perspex.Base.csproj

@@ -75,6 +75,7 @@
     <Compile Include="Threading\JobRunner.cs" />
     <Compile Include="Threading\PerspexScheduler.cs" />
     <Compile Include="Threading\PerspexSynchronizationContext.cs" />
+    <Compile Include="Threading\SingleThreadDispatcher.cs" />
     <Compile Include="Utilities\MathUtilities.cs" />
     <Compile Include="Utilities\TypeUtilities.cs" />
   </ItemGroup>

+ 2 - 0
src/Perspex.Base/Platform/IPclPlatformWrapper.cs

@@ -10,5 +10,7 @@ namespace Perspex.Platform
     public interface IPclPlatformWrapper
     {
         Assembly[] GetLoadedAssemblies();
+        void PostThreadPoolItem(Action cb);
+        IDisposable StartSystemTimer(TimeSpan interval, Action tick);
     }
 }

+ 15 - 12
src/Perspex.Base/Threading/Dispatcher.cs

@@ -15,26 +15,29 @@ namespace Perspex.Threading
     /// In Perspex, there is usually only a single <see cref="Dispatcher"/> in the application -
     /// the one for the UI thread, retrieved via the <see cref="UIThread"/> property.
     /// </remarks>
-    public static class Dispatcher
+    public class Dispatcher
     {
-        private static readonly JobRunner _jobRunner =
-            new JobRunner(PerspexLocator.Current.GetService<IPlatformThreadingInterface>());
+        private readonly IPlatformThreadingInterface _platform;
+        private readonly JobRunner _jobRunner;
 
-        /// <summary>
-        /// Initializes a new instance of the <see cref="Dispatcher"/> class.
-        /// </summary>
-        static Dispatcher()
+        public static Dispatcher UIThread { get; } =
+            new Dispatcher(PerspexLocator.Current.GetService<IPlatformThreadingInterface>());
+
+        public Dispatcher(IPlatformThreadingInterface platform)
         {
-            PerspexLocator.Current.GetService<IPlatformThreadingInterface>().Signaled += _jobRunner.RunJobs;
+            _platform = platform;
+            _jobRunner = new JobRunner(platform);
+            _platform.Signaled += _jobRunner.RunJobs;
         }
 
+
         /// <summary>
         /// Runs the dispatcher's main loop.
         /// </summary>
         /// <param name="cancellationToken">
         /// A cancellation token used to exit the main loop.
         /// </param>
-        public static void MainLoop(CancellationToken cancellationToken)
+        public void MainLoop(CancellationToken cancellationToken)
         {
             var platform = PerspexLocator.Current.GetService<IPlatformThreadingInterface>();
             cancellationToken.Register(platform.Signal);
@@ -44,7 +47,7 @@ namespace Perspex.Threading
         /// <summary>
         /// Runs continuations pushed on the loop.
         /// </summary>
-        public static void RunJobs()
+        public void RunJobs()
         {
             _jobRunner.RunJobs();
         }
@@ -55,7 +58,7 @@ namespace Perspex.Threading
         /// <param name="action">The method.</param>
         /// <param name="priority">The priority with which to invoke the method.</param>
         /// <returns>A task that can be used to track the method's execution.</returns>
-        public static Task InvokeAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal)
+        public Task InvokeAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal)
         {
             return _jobRunner.InvokeAsync(action, priority);
         }
@@ -65,7 +68,7 @@ namespace Perspex.Threading
         /// </summary>
         /// <param name="action">The method.</param>
         /// <param name="priority">The priority with which to invoke the method.</param>
-        internal static void Post(Action action, DispatcherPriority priority = DispatcherPriority.Normal)
+        internal void Post(Action action, DispatcherPriority priority = DispatcherPriority.Normal)
         {
             _jobRunner.Post(action, priority);
         }

+ 1 - 1
src/Perspex.Base/Threading/DispatcherTimer.cs

@@ -177,7 +177,7 @@ namespace Perspex.Threading
         /// </summary>
         private void InternalTick()
         {
-            Dispatcher.Post(RaiseTick, _priority);
+            Dispatcher.UIThread.Post(RaiseTick, _priority);
         }
 
         /// <summary>

+ 2 - 2
src/Perspex.Base/Threading/PerspexSynchronizationContext.cs

@@ -36,14 +36,14 @@ namespace Perspex.Threading
         /// <inheritdoc/>
         public override void Post(SendOrPostCallback d, object state)
         {
-            Dispatcher.Post(() => d(state));
+           Dispatcher.UIThread.Post(() => d(state));
         }
 
         /// <inheritdoc/>
         public override void Send(SendOrPostCallback d, object state)
         {
             // TODO: Add check for being on the main thread, we should invoke the method immediately in this case
-            Dispatcher.InvokeAsync(() => d(state)).Wait();
+            Dispatcher.UIThread.InvokeAsync(() => d(state)).Wait();
         }
     }
 }

+ 58 - 0
src/Perspex.Base/Threading/SingleThreadDispatcher.cs

@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Perspex.Platform;
+
+namespace Perspex.Threading
+{
+    public class SingleThreadDispatcher : Dispatcher
+    {
+        class ThreadingInterface : IPlatformThreadingInterface
+        {
+            private AutoResetEvent _evnt = new AutoResetEvent(false);
+            private JobRunner _timerJobRunner;
+
+            public ThreadingInterface()
+            {
+                _timerJobRunner = new JobRunner(this);
+            }
+
+            public void RunLoop(CancellationToken cancellationToken)
+            {
+                while (!cancellationToken.IsCancellationRequested)
+                {
+                    _evnt.WaitOne();
+                    if (cancellationToken.IsCancellationRequested)
+                        return;
+                    Signaled?.Invoke();
+                    _timerJobRunner.RunJobs();
+                }
+            }
+
+            public IDisposable StartTimer(TimeSpan interval, Action tick)
+                => PerspexLocator.Current.GetService<IPclPlatformWrapper>().StartSystemTimer(interval,
+                    () => _timerJobRunner.Post(tick, DispatcherPriority.Normal));
+
+            public void Signal() => _evnt.Set();
+
+            public event Action Signaled;
+        }
+
+        public SingleThreadDispatcher() : base(new ThreadingInterface())
+        {
+        }
+
+        public static Dispatcher StartNew(CancellationToken token)
+        {
+            var dispatcher = new SingleThreadDispatcher();
+            PerspexLocator.Current.GetService<IPclPlatformWrapper>().PostThreadPoolItem(() =>
+            {
+                dispatcher.MainLoop(token);
+            });
+            return dispatcher;
+        }
+    }
+}

+ 2 - 2
src/Perspex.Controls/TopLevel.cs

@@ -397,7 +397,7 @@ namespace Perspex.Controls
         /// </summary>
         private void HandleLayoutNeeded()
         {
-            Dispatcher.InvokeAsync(LayoutManager.ExecuteLayoutPass, DispatcherPriority.Render);
+            Dispatcher.UIThread.InvokeAsync(LayoutManager.ExecuteLayoutPass, DispatcherPriority.Render);
         }
 
         /// <summary>
@@ -413,7 +413,7 @@ namespace Perspex.Controls
         /// </summary>
         private void HandleRenderNeeded()
         {
-            Dispatcher.InvokeAsync(
+            Dispatcher.UIThread.InvokeAsync(
                 () => PlatformImpl.Invalidate(new Rect(ClientSize)),
                 DispatcherPriority.Render);
         }

+ 6 - 6
src/Perspex.HtmlRenderer/HtmlControl.cs

@@ -563,7 +563,7 @@ namespace Perspex.Controls.Html
             if (CheckAccess())
                 OnLoadComplete(e);
             else
-                Dispatcher.Invoke(new Action<HtmlLinkClickedEventArgs>(OnLinkClicked), e);
+                Dispatcher.UIThread.Invoke(new Action<HtmlLinkClickedEventArgs>(OnLinkClicked), e);
 
         }
 
@@ -572,7 +572,7 @@ namespace Perspex.Controls.Html
             if (CheckAccess())
                 OnLinkClicked(e);
             else
-                Dispatcher.Invoke(new Action<HtmlLinkClickedEventArgs>(OnLinkClicked), e);
+                Dispatcher.UIThread.Invoke(new Action<HtmlLinkClickedEventArgs>(OnLinkClicked), e);
         }
 
         private void OnRenderError(object sender, HtmlRenderErrorEventArgs e)
@@ -580,7 +580,7 @@ namespace Perspex.Controls.Html
             if (CheckAccess())
                 OnRenderError(e);
             else
-                Dispatcher.Invoke(new Action<HtmlRenderErrorEventArgs>(OnRenderError), e);
+                Dispatcher.UIThread.Invoke(new Action<HtmlRenderErrorEventArgs>(OnRenderError), e);
         }
 
         private void OnStylesheetLoad(object sender, HtmlStylesheetLoadEventArgs e)
@@ -588,7 +588,7 @@ namespace Perspex.Controls.Html
             if (CheckAccess())
                 OnStylesheetLoad(e);
             else
-                Dispatcher.Invoke(new Action<HtmlStylesheetLoadEventArgs>(OnStylesheetLoad), e);
+                Dispatcher.UIThread.Invoke(new Action<HtmlStylesheetLoadEventArgs>(OnStylesheetLoad), e);
         }
 
         private void OnImageLoad(object sender, HtmlImageLoadEventArgs e)
@@ -596,7 +596,7 @@ namespace Perspex.Controls.Html
             if (CheckAccess())
                 OnImageLoad(e);
             else
-                Dispatcher.Invoke(new Action<HtmlImageLoadEventArgs>(OnImageLoad), e);
+                Dispatcher.UIThread.Invoke(new Action<HtmlImageLoadEventArgs>(OnImageLoad), e);
         }
 
         private void OnRefresh(object sender, HtmlRefreshEventArgs e)
@@ -604,7 +604,7 @@ namespace Perspex.Controls.Html
             if (CheckAccess())
                 OnRefresh(e);
             else
-                Dispatcher.Invoke(new Action<HtmlRefreshEventArgs>(OnRefresh), e);
+                Dispatcher.UIThread.Invoke(new Action<HtmlRefreshEventArgs>(OnRefresh), e);
         }
         */
     }

BIN
src/Shared/PlatformSupport/PclPlatformWrapper.cs