Browse Source

Reverted Dispatcher.UIThread and added SingleThreadDispatcher

pull/213/head
Nikita Tsukanov 11 years ago
parent
commit
f50a2c361c
  1. 2
      src/Perspex.Application/Application.cs
  2. 1
      src/Perspex.Base/Perspex.Base.csproj
  3. 2
      src/Perspex.Base/Platform/IPclPlatformWrapper.cs
  4. 27
      src/Perspex.Base/Threading/Dispatcher.cs
  5. 2
      src/Perspex.Base/Threading/DispatcherTimer.cs
  6. 4
      src/Perspex.Base/Threading/PerspexSynchronizationContext.cs
  7. 58
      src/Perspex.Base/Threading/SingleThreadDispatcher.cs
  8. 4
      src/Perspex.Controls/TopLevel.cs
  9. 12
      src/Perspex.HtmlRenderer/HtmlControl.cs
  10. BIN
      src/Shared/PlatformSupport/PclPlatformWrapper.cs

2
src/Perspex.Application/Application.cs

@ -144,7 +144,7 @@ namespace Perspex
{ {
var source = new CancellationTokenSource(); var source = new CancellationTokenSource();
closable.Closed += (s, e) => source.Cancel(); closable.Closed += (s, e) => source.Cancel();
Dispatcher.MainLoop(source.Token); Dispatcher.UIThread.MainLoop(source.Token);
} }
/// <summary> /// <summary>

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

@ -75,6 +75,7 @@
<Compile Include="Threading\JobRunner.cs" /> <Compile Include="Threading\JobRunner.cs" />
<Compile Include="Threading\PerspexScheduler.cs" /> <Compile Include="Threading\PerspexScheduler.cs" />
<Compile Include="Threading\PerspexSynchronizationContext.cs" /> <Compile Include="Threading\PerspexSynchronizationContext.cs" />
<Compile Include="Threading\SingleThreadDispatcher.cs" />
<Compile Include="Utilities\MathUtilities.cs" /> <Compile Include="Utilities\MathUtilities.cs" />
<Compile Include="Utilities\TypeUtilities.cs" /> <Compile Include="Utilities\TypeUtilities.cs" />
</ItemGroup> </ItemGroup>

2
src/Perspex.Base/Platform/IPclPlatformWrapper.cs

@ -10,5 +10,7 @@ namespace Perspex.Platform
public interface IPclPlatformWrapper public interface IPclPlatformWrapper
{ {
Assembly[] GetLoadedAssemblies(); Assembly[] GetLoadedAssemblies();
void PostThreadPoolItem(Action cb);
IDisposable StartSystemTimer(TimeSpan interval, Action tick);
} }
} }

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

@ -15,26 +15,29 @@ namespace Perspex.Threading
/// In Perspex, there is usually only a single <see cref="Dispatcher"/> in the application - /// In Perspex, there is usually only a single <see cref="Dispatcher"/> in the application -
/// the one for the UI thread, retrieved via the <see cref="UIThread"/> property. /// the one for the UI thread, retrieved via the <see cref="UIThread"/> property.
/// </remarks> /// </remarks>
public static class Dispatcher public class Dispatcher
{ {
private static readonly JobRunner _jobRunner = private readonly IPlatformThreadingInterface _platform;
new JobRunner(PerspexLocator.Current.GetService<IPlatformThreadingInterface>()); private readonly JobRunner _jobRunner;
/// <summary> public static Dispatcher UIThread { get; } =
/// Initializes a new instance of the <see cref="Dispatcher"/> class. new Dispatcher(PerspexLocator.Current.GetService<IPlatformThreadingInterface>());
/// </summary>
static Dispatcher() public Dispatcher(IPlatformThreadingInterface platform)
{ {
PerspexLocator.Current.GetService<IPlatformThreadingInterface>().Signaled += _jobRunner.RunJobs; _platform = platform;
_jobRunner = new JobRunner(platform);
_platform.Signaled += _jobRunner.RunJobs;
} }
/// <summary> /// <summary>
/// Runs the dispatcher's main loop. /// Runs the dispatcher's main loop.
/// </summary> /// </summary>
/// <param name="cancellationToken"> /// <param name="cancellationToken">
/// A cancellation token used to exit the main loop. /// A cancellation token used to exit the main loop.
/// </param> /// </param>
public static void MainLoop(CancellationToken cancellationToken) public void MainLoop(CancellationToken cancellationToken)
{ {
var platform = PerspexLocator.Current.GetService<IPlatformThreadingInterface>(); var platform = PerspexLocator.Current.GetService<IPlatformThreadingInterface>();
cancellationToken.Register(platform.Signal); cancellationToken.Register(platform.Signal);
@ -44,7 +47,7 @@ namespace Perspex.Threading
/// <summary> /// <summary>
/// Runs continuations pushed on the loop. /// Runs continuations pushed on the loop.
/// </summary> /// </summary>
public static void RunJobs() public void RunJobs()
{ {
_jobRunner.RunJobs(); _jobRunner.RunJobs();
} }
@ -55,7 +58,7 @@ namespace Perspex.Threading
/// <param name="action">The method.</param> /// <param name="action">The method.</param>
/// <param name="priority">The priority with which to invoke the method.</param> /// <param name="priority">The priority with which to invoke the method.</param>
/// <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 static Task InvokeAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal) public Task InvokeAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal)
{ {
return _jobRunner.InvokeAsync(action, priority); return _jobRunner.InvokeAsync(action, priority);
} }
@ -65,7 +68,7 @@ namespace Perspex.Threading
/// </summary> /// </summary>
/// <param name="action">The method.</param> /// <param name="action">The method.</param>
/// <param name="priority">The priority with which to invoke the method.</param> /// <param name="priority">The priority with which to invoke the method.</param>
internal static void Post(Action action, DispatcherPriority priority = DispatcherPriority.Normal) internal void Post(Action action, DispatcherPriority priority = DispatcherPriority.Normal)
{ {
_jobRunner.Post(action, priority); _jobRunner.Post(action, priority);
} }

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

@ -177,7 +177,7 @@ namespace Perspex.Threading
/// </summary> /// </summary>
private void InternalTick() private void InternalTick()
{ {
Dispatcher.Post(RaiseTick, _priority); Dispatcher.UIThread.Post(RaiseTick, _priority);
} }
/// <summary> /// <summary>

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

@ -36,14 +36,14 @@ namespace Perspex.Threading
/// <inheritdoc/> /// <inheritdoc/>
public override void Post(SendOrPostCallback d, object state) public override void Post(SendOrPostCallback d, object state)
{ {
Dispatcher.Post(() => d(state)); Dispatcher.UIThread.Post(() => d(state));
} }
/// <inheritdoc/> /// <inheritdoc/>
public override void Send(SendOrPostCallback d, object state) 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 // TODO: Add check for being on the main thread, we should invoke the method immediately in this case
Dispatcher.InvokeAsync(() => d(state)).Wait(); Dispatcher.UIThread.InvokeAsync(() => d(state)).Wait();
} }
} }
} }

58
src/Perspex.Base/Threading/SingleThreadDispatcher.cs

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Perspex.Platform;
namespace Perspex.Threading
{
public class SingleThreadDispatcher : Dispatcher
{
class ThreadingInterface : IPlatformThreadingInterface
{
private AutoResetEvent _evnt = new AutoResetEvent(false);
private JobRunner _timerJobRunner;
public ThreadingInterface()
{
_timerJobRunner = new JobRunner(this);
}
public void RunLoop(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
_evnt.WaitOne();
if (cancellationToken.IsCancellationRequested)
return;
Signaled?.Invoke();
_timerJobRunner.RunJobs();
}
}
public IDisposable StartTimer(TimeSpan interval, Action tick)
=> PerspexLocator.Current.GetService<IPclPlatformWrapper>().StartSystemTimer(interval,
() => _timerJobRunner.Post(tick, DispatcherPriority.Normal));
public void Signal() => _evnt.Set();
public event Action Signaled;
}
public SingleThreadDispatcher() : base(new ThreadingInterface())
{
}
public static Dispatcher StartNew(CancellationToken token)
{
var dispatcher = new SingleThreadDispatcher();
PerspexLocator.Current.GetService<IPclPlatformWrapper>().PostThreadPoolItem(() =>
{
dispatcher.MainLoop(token);
});
return dispatcher;
}
}
}

4
src/Perspex.Controls/TopLevel.cs

@ -397,7 +397,7 @@ namespace Perspex.Controls
/// </summary> /// </summary>
private void HandleLayoutNeeded() private void HandleLayoutNeeded()
{ {
Dispatcher.InvokeAsync(LayoutManager.ExecuteLayoutPass, DispatcherPriority.Render); Dispatcher.UIThread.InvokeAsync(LayoutManager.ExecuteLayoutPass, DispatcherPriority.Render);
} }
/// <summary> /// <summary>
@ -413,7 +413,7 @@ namespace Perspex.Controls
/// </summary> /// </summary>
private void HandleRenderNeeded() private void HandleRenderNeeded()
{ {
Dispatcher.InvokeAsync( Dispatcher.UIThread.InvokeAsync(
() => PlatformImpl.Invalidate(new Rect(ClientSize)), () => PlatformImpl.Invalidate(new Rect(ClientSize)),
DispatcherPriority.Render); DispatcherPriority.Render);
} }

12
src/Perspex.HtmlRenderer/HtmlControl.cs

@ -563,7 +563,7 @@ namespace Perspex.Controls.Html
if (CheckAccess()) if (CheckAccess())
OnLoadComplete(e); OnLoadComplete(e);
else else
Dispatcher.Invoke(new Action<HtmlLinkClickedEventArgs>(OnLinkClicked), e); Dispatcher.UIThread.Invoke(new Action<HtmlLinkClickedEventArgs>(OnLinkClicked), e);
} }
@ -572,7 +572,7 @@ namespace Perspex.Controls.Html
if (CheckAccess()) if (CheckAccess())
OnLinkClicked(e); OnLinkClicked(e);
else else
Dispatcher.Invoke(new Action<HtmlLinkClickedEventArgs>(OnLinkClicked), e); Dispatcher.UIThread.Invoke(new Action<HtmlLinkClickedEventArgs>(OnLinkClicked), e);
} }
private void OnRenderError(object sender, HtmlRenderErrorEventArgs e) private void OnRenderError(object sender, HtmlRenderErrorEventArgs e)
@ -580,7 +580,7 @@ namespace Perspex.Controls.Html
if (CheckAccess()) if (CheckAccess())
OnRenderError(e); OnRenderError(e);
else else
Dispatcher.Invoke(new Action<HtmlRenderErrorEventArgs>(OnRenderError), e); Dispatcher.UIThread.Invoke(new Action<HtmlRenderErrorEventArgs>(OnRenderError), e);
} }
private void OnStylesheetLoad(object sender, HtmlStylesheetLoadEventArgs e) private void OnStylesheetLoad(object sender, HtmlStylesheetLoadEventArgs e)
@ -588,7 +588,7 @@ namespace Perspex.Controls.Html
if (CheckAccess()) if (CheckAccess())
OnStylesheetLoad(e); OnStylesheetLoad(e);
else else
Dispatcher.Invoke(new Action<HtmlStylesheetLoadEventArgs>(OnStylesheetLoad), e); Dispatcher.UIThread.Invoke(new Action<HtmlStylesheetLoadEventArgs>(OnStylesheetLoad), e);
} }
private void OnImageLoad(object sender, HtmlImageLoadEventArgs e) private void OnImageLoad(object sender, HtmlImageLoadEventArgs e)
@ -596,7 +596,7 @@ namespace Perspex.Controls.Html
if (CheckAccess()) if (CheckAccess())
OnImageLoad(e); OnImageLoad(e);
else else
Dispatcher.Invoke(new Action<HtmlImageLoadEventArgs>(OnImageLoad), e); Dispatcher.UIThread.Invoke(new Action<HtmlImageLoadEventArgs>(OnImageLoad), e);
} }
private void OnRefresh(object sender, HtmlRefreshEventArgs e) private void OnRefresh(object sender, HtmlRefreshEventArgs e)
@ -604,7 +604,7 @@ namespace Perspex.Controls.Html
if (CheckAccess()) if (CheckAccess())
OnRefresh(e); OnRefresh(e);
else else
Dispatcher.Invoke(new Action<HtmlRefreshEventArgs>(OnRefresh), e); Dispatcher.UIThread.Invoke(new Action<HtmlRefreshEventArgs>(OnRefresh), e);
} }
*/ */
} }

BIN
src/Shared/PlatformSupport/PclPlatformWrapper.cs

Binary file not shown.
Loading…
Cancel
Save