diff --git a/Perspex.Base/Perspex.Base.csproj b/Perspex.Base/Perspex.Base.csproj
index 18f0441456..715391fbfa 100644
--- a/Perspex.Base/Perspex.Base.csproj
+++ b/Perspex.Base/Perspex.Base.csproj
@@ -54,6 +54,7 @@
+
diff --git a/Perspex.Base/Platform/IPlatformThreadingInterface.cs b/Perspex.Base/Platform/IPlatformThreadingInterface.cs
index 8f7282e0ad..d594abeb49 100644
--- a/Perspex.Base/Platform/IPlatformThreadingInterface.cs
+++ b/Perspex.Base/Platform/IPlatformThreadingInterface.cs
@@ -16,6 +16,8 @@ namespace Perspex.Platform
///
public interface IPlatformThreadingInterface
{
+ bool HasMessages();
+
///
/// Process a single message from the windowing system, blocking until one is available.
///
diff --git a/Perspex.Base/Threading/DispatcherTimer.cs b/Perspex.Base/Threading/DispatcherTimer.cs
index b7912fa983..04230fef7c 100644
--- a/Perspex.Base/Threading/DispatcherTimer.cs
+++ b/Perspex.Base/Threading/DispatcherTimer.cs
@@ -7,6 +7,7 @@
namespace Perspex.Threading
{
using System;
+ using System.Reactive.Disposables;
using Perspex.Platform;
using Splat;
@@ -105,6 +106,24 @@ namespace Perspex.Threading
set;
}
+ public static IDisposable Run(Func action, TimeSpan interval, DispatcherPriority priority = DispatcherPriority.Normal)
+ {
+ var timer = new DispatcherTimer(priority);
+
+ timer.Interval = interval;
+ timer.Tick += (s, e) =>
+ {
+ if (!action())
+ {
+ timer.Stop();
+ }
+ };
+
+ timer.Start();
+
+ return Disposable.Create(() => timer.Stop());
+ }
+
public void Start()
{
if (!this.IsEnabled)
diff --git a/Perspex.Base/Threading/MainLoop.cs b/Perspex.Base/Threading/MainLoop.cs
index 88afba36a6..f53aeee5d5 100644
--- a/Perspex.Base/Threading/MainLoop.cs
+++ b/Perspex.Base/Threading/MainLoop.cs
@@ -30,14 +30,21 @@ namespace Perspex.Win32.Threading
{
while (!cancellationToken.IsCancellationRequested)
{
- Job job;
+ Job job = null;
- // TODO: Dispatch windows messages in preference to lower priority jobs.
- while (this.queue.Count > 0)
+ while (job != null || this.queue.Count > 0)
{
- lock (this.queue)
+ if (job == null)
{
- job = this.queue.Dequeue();
+ lock (this.queue)
+ {
+ job = this.queue.Dequeue();
+ }
+ }
+
+ if (job.Priority < DispatcherPriority.Input && platform.HasMessages())
+ {
+ break;
}
try
@@ -49,6 +56,8 @@ namespace Perspex.Win32.Threading
{
job.TaskCompletionSource.SetException(e);
}
+
+ job = null;
}
platform.ProcessMessage();
@@ -57,7 +66,7 @@ namespace Perspex.Win32.Threading
public Task InvokeAsync(Action action, DispatcherPriority priority)
{
- var job = new Job(action);
+ var job = new Job(action, priority);
lock (this.queue)
{
@@ -70,14 +79,17 @@ namespace Perspex.Win32.Threading
private class Job
{
- public Job(Action action)
+ public Job(Action action, DispatcherPriority priority)
{
this.Action = action;
+ this.Priority = priority;
this.TaskCompletionSource = new TaskCompletionSource