Browse Source

Merge pull request #95 from kekekeks/master

Added SynchronizationContext support
pull/97/head
Steven Kirk 11 years ago
parent
commit
8efbf6053e
  1. 1
      src/Perspex.Application/Application.cs
  2. 1
      src/Perspex.Base/Perspex.Base.csproj
  3. 10
      src/Perspex.Base/Threading/Dispatcher.cs
  4. 2
      src/Perspex.Base/Threading/DispatcherTimer.cs
  5. 42
      src/Perspex.Base/Threading/MainLoop.cs
  6. 47
      src/Perspex.Base/Threading/PerspexSynchronizationContext.cs
  7. 4
      src/Perspex.ReactiveUI/Registrations.cs

1
src/Perspex.Application/Application.cs

@ -150,6 +150,7 @@ namespace Perspex
/// </summary> /// </summary>
protected virtual void RegisterServices() protected virtual void RegisterServices()
{ {
PerspexSynchronizationContext.InstallIfNeeded();
this.FocusManager = new FocusManager(); this.FocusManager = new FocusManager();
this.InputManager = new InputManager(); this.InputManager = new InputManager();

1
src/Perspex.Base/Perspex.Base.csproj

@ -72,6 +72,7 @@
<Compile Include="Threading\DispatcherTimer.cs" /> <Compile Include="Threading\DispatcherTimer.cs" />
<Compile Include="Threading\MainLoop.cs" /> <Compile Include="Threading\MainLoop.cs" />
<Compile Include="Threading\PerspexScheduler.cs" /> <Compile Include="Threading\PerspexScheduler.cs" />
<Compile Include="Threading\PerspexSynchronizationContext.cs" />
<Compile Include="Utilities\MathUtilities.cs" /> <Compile Include="Utilities\MathUtilities.cs" />
<Compile Include="Utilities\TypeUtilities.cs" /> <Compile Include="Utilities\TypeUtilities.cs" />
</ItemGroup> </ItemGroup>

10
src/Perspex.Base/Threading/Dispatcher.cs

@ -68,5 +68,15 @@ namespace Perspex.Threading
{ {
return this.mainLoop.InvokeAsync(action, priority); return this.mainLoop.InvokeAsync(action, priority);
} }
/// <summary>
/// Post action that will be invoked on main thread
/// </summary>
/// <param name="action">The method.</param>
/// <param name="priority">The priority with which to invoke the method.</param>
internal void Post(Action action, DispatcherPriority priority = DispatcherPriority.Normal)
{
this.mainLoop.Post(action, priority);
}
} }
} }

2
src/Perspex.Base/Threading/DispatcherTimer.cs

@ -203,7 +203,7 @@ namespace Perspex.Threading
/// </summary> /// </summary>
private void InternalTick() private void InternalTick()
{ {
this.Dispatcher.InvokeAsync(this.RaiseTick, this.priority); this.Dispatcher.Post(this.RaiseTick, this.priority);
} }
/// <summary> /// <summary>

42
src/Perspex.Base/Threading/MainLoop.cs

@ -70,14 +70,21 @@ namespace Perspex.Win32.Threading
break; break;
} }
try if (job.TaskCompletionSource == null)
{ {
job.Action(); job.Action();
job.TaskCompletionSource.SetResult(null);
} }
catch (Exception e) else
{ {
job.TaskCompletionSource.SetException(e); try
{
job.Action();
job.TaskCompletionSource.SetResult(null);
}
catch (Exception e)
{
job.TaskCompletionSource.SetException(e);
}
} }
job = null; job = null;
@ -92,15 +99,29 @@ namespace Perspex.Win32.Threading
/// <returns>A task that can be used to track the method's execution.</returns> /// <returns>A task that can be used to track the method's execution.</returns>
public Task InvokeAsync(Action action, DispatcherPriority priority) 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;
}
/// <summary>
/// Post action that will be invoked on main thread
/// </summary>
/// <param name="action">The method.</param>
///
/// <param name="priority">The priority with which to invoke the method.</param>
internal void Post(Action action, DispatcherPriority priority)
{
this.AddJob(new Job(action, priority, true));
}
private void AddJob(Job job)
{
lock (this.queue) lock (this.queue)
{ {
this.queue.Add(job, priority); this.queue.Add(job, job.Priority);
} }
platform.Wake(); platform.Wake();
return job.TaskCompletionSource.Task;
} }
/// <summary> /// <summary>
@ -113,11 +134,12 @@ namespace Perspex.Win32.Threading
/// </summary> /// </summary>
/// <param name="action">The method to call.</param> /// <param name="action">The method to call.</param>
/// <param name="priority">The job priority.</param> /// <param name="priority">The job priority.</param>
public Job(Action action, DispatcherPriority priority) /// <param name="throwOnUiThread">Do not wrap excepption in TaskCompletionSource</param>
public Job(Action action, DispatcherPriority priority, bool throwOnUiThread)
{ {
this.Action = action; this.Action = action;
this.Priority = priority; this.Priority = priority;
this.TaskCompletionSource = new TaskCompletionSource<object>(); this.TaskCompletionSource = throwOnUiThread ? null : new TaskCompletionSource<object>();
} }
/// <summary> /// <summary>

47
src/Perspex.Base/Threading/PerspexSynchronizationContext.cs

@ -0,0 +1,47 @@
namespace Perspex.Threading
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
/// <summary>
/// SynchronizationContext to be used on main thread
/// </summary>
public class PerspexSynchronizationContext : SynchronizationContext
{
/// <summary>
/// Controls if SynchronizationContext should be installed in InstallIfNeeded. Used by Designer.
/// </summary>
public static bool AutoInstall { get; set; } = true;
/// <summary>
/// Installs synchronization context in current thread
/// </summary>
public static void InstallIfNeeded()
{
if (!AutoInstall || Current is PerspexSynchronizationContext)
{
return;
}
SetSynchronizationContext(new PerspexSynchronizationContext());
}
/// <inheritdoc/>
public override void Post(SendOrPostCallback d, object 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.UIThread.InvokeAsync(() => d(state)).Wait();
}
}
}

4
src/Perspex.ReactiveUI/Registrations.cs

@ -1,4 +1,6 @@
using System; using System;
using System.Reactive.Concurrency;
using System.Threading;
namespace ReactiveUI namespace ReactiveUI
@ -12,7 +14,7 @@ namespace ReactiveUI
{ {
public void Register(Action<Func<object>, Type> registerFunction) public void Register(Action<Func<object>, Type> registerFunction)
{ {
RxApp.MainThreadScheduler = new SynchronizationContextScheduler(SynchronizationContext.Current);
} }
} }
} }

Loading…
Cancel
Save