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>
protected virtual void RegisterServices()
{
PerspexSynchronizationContext.InstallIfNeeded();
this.FocusManager = new FocusManager();
this.InputManager = new InputManager();

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

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

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

@ -68,5 +68,15 @@ namespace Perspex.Threading
{
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>
private void InternalTick()
{
this.Dispatcher.InvokeAsync(this.RaiseTick, this.priority);
this.Dispatcher.Post(this.RaiseTick, this.priority);
}
/// <summary>

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

@ -70,14 +70,21 @@ namespace Perspex.Win32.Threading
break;
}
try
if (job.TaskCompletionSource == null)
{
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;
@ -92,15 +99,29 @@ namespace Perspex.Win32.Threading
/// <returns>A task that can be used to track the method's execution.</returns>
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)
{
this.queue.Add(job, priority);
this.queue.Add(job, job.Priority);
}
platform.Wake();
return job.TaskCompletionSource.Task;
}
/// <summary>
@ -113,11 +134,12 @@ namespace Perspex.Win32.Threading
/// </summary>
/// <param name="action">The method to call.</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.Priority = priority;
this.TaskCompletionSource = new TaskCompletionSource<object>();
this.TaskCompletionSource = throwOnUiThread ? null : new TaskCompletionSource<object>();
}
/// <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.Reactive.Concurrency;
using System.Threading;
namespace ReactiveUI
@ -12,7 +14,7 @@ namespace ReactiveUI
{
public void Register(Action<Func<object>, Type> registerFunction)
{
RxApp.MainThreadScheduler = new SynchronizationContextScheduler(SynchronizationContext.Current);
}
}
}

Loading…
Cancel
Save