diff --git a/src/Perspex.Application/Application.cs b/src/Perspex.Application/Application.cs
index 1b94ecaa51..40c3542d8c 100644
--- a/src/Perspex.Application/Application.cs
+++ b/src/Perspex.Application/Application.cs
@@ -150,6 +150,7 @@ namespace Perspex
///
protected virtual void RegisterServices()
{
+ PerspexSynchronizationContext.InstallIfNeeded();
this.FocusManager = new FocusManager();
this.InputManager = new InputManager();
diff --git a/src/Perspex.Base/Perspex.Base.csproj b/src/Perspex.Base/Perspex.Base.csproj
index 654fbb3926..d5723e5a6d 100644
--- a/src/Perspex.Base/Perspex.Base.csproj
+++ b/src/Perspex.Base/Perspex.Base.csproj
@@ -72,6 +72,7 @@
+
diff --git a/src/Perspex.Base/Threading/Dispatcher.cs b/src/Perspex.Base/Threading/Dispatcher.cs
index af6f1d58af..d959151543 100644
--- a/src/Perspex.Base/Threading/Dispatcher.cs
+++ b/src/Perspex.Base/Threading/Dispatcher.cs
@@ -50,6 +50,14 @@ namespace Perspex.Threading
this.mainLoop.Run(cancellationToken);
}
+ ///
+ /// Runs continuations pushed on the loop.
+ ///
+ public void RunJobs()
+ {
+ this.mainLoop.RunJobs();
+ }
+
///
/// Invokes a method on the dispatcher thread.
///
@@ -60,5 +68,15 @@ namespace Perspex.Threading
{
return this.mainLoop.InvokeAsync(action, priority);
}
+
+ ///
+ /// Post action that will be invoked on main thread
+ ///
+ /// The method.
+ /// The priority with which to invoke the method.
+ internal void Post(Action action, DispatcherPriority priority = DispatcherPriority.Normal)
+ {
+ this.mainLoop.Post(action, priority);
+ }
}
}
\ No newline at end of file
diff --git a/src/Perspex.Base/Threading/DispatcherTimer.cs b/src/Perspex.Base/Threading/DispatcherTimer.cs
index 73335ea408..0d49bb21f8 100644
--- a/src/Perspex.Base/Threading/DispatcherTimer.cs
+++ b/src/Perspex.Base/Threading/DispatcherTimer.cs
@@ -203,7 +203,7 @@ namespace Perspex.Threading
///
private void InternalTick()
{
- this.Dispatcher.InvokeAsync(this.RaiseTick, this.priority);
+ this.Dispatcher.Post(this.RaiseTick, this.priority);
}
///
diff --git a/src/Perspex.Base/Threading/MainLoop.cs b/src/Perspex.Base/Threading/MainLoop.cs
index e7efefacc1..3a99133d15 100644
--- a/src/Perspex.Base/Threading/MainLoop.cs
+++ b/src/Perspex.Base/Threading/MainLoop.cs
@@ -42,23 +42,40 @@ namespace Perspex.Win32.Threading
{
while (!cancellationToken.IsCancellationRequested)
{
- Job job = null;
+ RunJobs();
- while (job != null || this.queue.Count > 0)
+ platform.ProcessMessage();
+ }
+ }
+
+ ///
+ /// Runs continuations pushed on the loop.
+ ///
+ public void RunJobs()
+ {
+ Job job = null;
+
+ while (job != null || this.queue.Count > 0)
+ {
+ if (job == null)
{
- if (job == null)
+ lock (this.queue)
{
- lock (this.queue)
- {
- job = this.queue.Dequeue();
- }
+ job = this.queue.Dequeue();
}
+ }
- if (job.Priority < DispatcherPriority.Input && platform.HasMessages())
- {
- break;
- }
+ if (job.Priority < DispatcherPriority.Input && platform.HasMessages())
+ {
+ break;
+ }
+ if (job.TaskCompletionSource == null)
+ {
+ job.Action();
+ }
+ else
+ {
try
{
job.Action();
@@ -68,11 +85,9 @@ namespace Perspex.Win32.Threading
{
job.TaskCompletionSource.SetException(e);
}
-
- job = null;
}
- platform.ProcessMessage();
+ job = null;
}
}
@@ -84,15 +99,29 @@ namespace Perspex.Win32.Threading
/// A task that can be used to track the method's execution.
public Task InvokeAsync(Action action, DispatcherPriority priority)
{
- var job = new Job(action, priority);
+ var job = new Job(action, priority, false);
+ this.AddJob(job);
+ return job.TaskCompletionSource.Task;
+ }
+ ///
+ /// Post action that will be invoked on main thread
+ ///
+ /// The method.
+ ///
+ /// The priority with which to invoke the method.
+ internal void Post(Action action, DispatcherPriority priority)
+ {
+ this.AddJob(new Job(action, priority, true));
+ }
+
+ private void AddJob(Job job)
+ {
lock (this.queue)
{
- this.queue.Add(job, priority);
+ this.queue.Add(job, job.Priority);
}
-
platform.Wake();
- return job.TaskCompletionSource.Task;
}
///
@@ -105,11 +134,12 @@ namespace Perspex.Win32.Threading
///
/// The method to call.
/// The job priority.
- public Job(Action action, DispatcherPriority priority)
+ /// Do not wrap excepption in TaskCompletionSource
+ public Job(Action action, DispatcherPriority priority, bool throwOnUiThread)
{
this.Action = action;
this.Priority = priority;
- this.TaskCompletionSource = new TaskCompletionSource