Browse Source

Added SynchronizationContext support

pull/95/head
Nikita Tsukanov 11 years ago
parent
commit
99af4bfdb3
  1. 2
      src/Perspex.Application/Application.cs
  2. 1
      src/Perspex.Base/Perspex.Base.csproj
  3. 3
      src/Perspex.Base/PerspexObject.cs
  4. 9
      src/Perspex.Base/Threading/Dispatcher.cs
  5. 40
      src/Perspex.Base/Threading/MainLoop.cs
  6. 47
      src/Perspex.Base/Threading/PerspexSynchronizationContext.cs

2
src/Perspex.Application/Application.cs

@ -55,7 +55,7 @@ namespace Perspex
{
throw new InvalidOperationException("Cannot create more than one Application instance.");
}
PerspexSynchronizationContext.InstallIfNeeded();
Current = this;
}

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>

3
src/Perspex.Base/PerspexObject.cs

@ -4,6 +4,8 @@
// </copyright>
// -----------------------------------------------------------------------
using Perspex.Threading;
namespace Perspex
{
using System;
@ -100,6 +102,7 @@ namespace Perspex
/// </summary>
public PerspexObject()
{
PerspexSynchronizationContext.InstallIfNeeded();
this.propertyLog = Log.ForContext(new[]
{
new PropertyEnricher("Area", "Property"),

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

@ -68,5 +68,14 @@ 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>
internal void Post(Action action)
{
this.mainLoop.Post(action);
}
}
}

40
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,27 @@ 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>
internal void Post(Action action)
{
this.AddJob(new Job(action, DispatcherPriority.Normal, 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 +132,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 @@
using System.Threading;
namespace Perspex.Threading
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/// <summary>
/// SynchronizationContext to be used on main thread
/// </summary>
public class PerspexSynchronizationContext : SynchronizationContext
{
/// <summary>
/// Controls if SynchronizationContext should be installed in InstallIfNeeded
/// </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();
}
}
}
Loading…
Cancel
Save