Browse Source

Added VerifyAccess call to PerspexObject. We need to do something about Dispatcher and unit tests

pull/261/head
Nikita Tsukanov 11 years ago
parent
commit
d1c6b50911
  1. 4
      src/Gtk/Perspex.Gtk/GtkPlatform.cs
  2. 18
      src/Perspex.Base/PerspexObject.cs
  3. 2
      src/Perspex.Base/Platform/IPlatformThreadingInterface.cs
  4. 17
      src/Perspex.Base/Threading/Dispatcher.cs
  5. 5
      src/Perspex.Base/Threading/SingleThreadDispatcher.cs
  6. 4
      src/Windows/Perspex.Win32/Win32Platform.cs

4
src/Gtk/Perspex.Gtk/GtkPlatform.cs

@ -17,6 +17,7 @@ namespace Perspex.Gtk
public class GtkPlatform : IPlatformThreadingInterface, IPlatformSettings
{
private static readonly GtkPlatform s_instance = new GtkPlatform();
private static Thread _uiThread;
public GtkPlatform()
{
@ -40,6 +41,7 @@ namespace Perspex.Gtk
.Bind<IPlatformThreadingInterface>().ToConstant(s_instance)
.Bind<ISystemDialogImpl>().ToSingleton<SystemDialogImpl>();
SharedPlatform.Register();
_uiThread = Thread.CurrentThread;
}
public bool HasMessages()
@ -79,6 +81,8 @@ namespace Perspex.Gtk
Gtk.Application.Invoke(delegate { Signaled?.Invoke(); });
}
public bool CheckForLoopThread() => Thread.CurrentThread == _uiThread;
public event Action Signaled;
}
}

18
src/Perspex.Base/PerspexObject.cs

@ -10,6 +10,7 @@ using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Reflection;
using Perspex.Reactive;
using Perspex.Threading;
using Perspex.Utilities;
using Serilog;
using Serilog.Core.Enrichers;
@ -300,6 +301,10 @@ namespace Perspex
}
}
public bool CheckAccess() => Dispatcher.UIThread.CheckAccess();
public void VerifyAccess() => Dispatcher.UIThread.VerifyAccess();
/// <summary>
/// Clears a <see cref="PerspexProperty"/>'s local value.
/// </summary>
@ -495,7 +500,7 @@ namespace Perspex
BindingPriority priority = BindingPriority.LocalValue)
{
Contract.Requires<ArgumentNullException>(property != null);
VerifyAccess();
if (property.IsDirect)
{
property = GetRegistered(property);
@ -556,7 +561,7 @@ namespace Perspex
BindingPriority priority = BindingPriority.LocalValue)
{
Contract.Requires<ArgumentNullException>(property != null);
VerifyAccess();
if (property.IsDirect)
{
property = (PerspexProperty<T>)GetRegistered(property);
@ -590,7 +595,7 @@ namespace Perspex
BindingPriority priority = BindingPriority.LocalValue)
{
Contract.Requires<ArgumentNullException>(property != null);
VerifyAccess();
if (property.IsDirect)
{
property = GetRegistered(property);
@ -650,7 +655,7 @@ namespace Perspex
BindingPriority priority = BindingPriority.LocalValue)
{
Contract.Requires<ArgumentNullException>(property != null);
VerifyAccess();
if (property.IsDirect)
{
property = (PerspexProperty<T>)GetRegistered(property);
@ -687,6 +692,7 @@ namespace Perspex
PerspexProperty sourceProperty,
BindingPriority priority = BindingPriority.LocalValue)
{
VerifyAccess();
_propertyLog.Verbose(
"Bound two way {Property} to {Binding} with priority {Priority}",
property,
@ -716,6 +722,7 @@ namespace Perspex
ISubject<object> source,
BindingPriority priority = BindingPriority.LocalValue)
{
VerifyAccess();
_propertyLog.Verbose(
"Bound two way {Property} to {Binding} with priority {Priority}",
property,
@ -733,6 +740,7 @@ namespace Perspex
/// <param name="property">The property.</param>
public void Revalidate(PerspexProperty property)
{
VerifyAccess();
PriorityValue value;
if (_values.TryGetValue(property, out value))
@ -788,6 +796,7 @@ namespace Perspex
BindingPriority priority)
{
Contract.Requires<ArgumentNullException>(property != null);
VerifyAccess();
PerspexPropertyChangedEventArgs e = new PerspexPropertyChangedEventArgs(
this,
@ -824,6 +833,7 @@ namespace Perspex
/// </returns>
protected bool SetAndRaise<T>(PerspexProperty<T> property, ref T field, T value)
{
VerifyAccess();
if (!object.Equals(field, value))
{
var old = field;

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

@ -26,6 +26,8 @@ namespace Perspex.Platform
/// </summary>
void Signal();
bool CheckForLoopThread();
event Action Signaled;
}

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

@ -26,10 +26,21 @@ namespace Perspex.Threading
public Dispatcher(IPlatformThreadingInterface platform)
{
_platform = platform;
if(_platform == null)
//TODO: Unit test mode, fix that somehow
return;
_jobRunner = new JobRunner(platform);
_platform.Signaled += _jobRunner.RunJobs;
}
public bool CheckAccess() => _platform?.CheckForLoopThread() ?? true;
public void VerifyAccess()
{
if (!CheckAccess())
throw new InvalidOperationException("Call from invalid thread");
}
/// <summary>
/// Runs the dispatcher's main loop.
@ -49,7 +60,7 @@ namespace Perspex.Threading
/// </summary>
public void RunJobs()
{
_jobRunner.RunJobs();
_jobRunner?.RunJobs();
}
/// <summary>
@ -60,7 +71,7 @@ namespace Perspex.Threading
/// <returns>A task that can be used to track the method's execution.</returns>
public Task InvokeTaskAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal)
{
return _jobRunner.InvokeAsync(action, priority);
return _jobRunner?.InvokeAsync(action, priority);
}
/// <summary>
@ -70,7 +81,7 @@ namespace Perspex.Threading
/// <param name="priority">The priority with which to invoke the method.</param>
public void InvokeAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal)
{
_jobRunner.Post(action, priority);
_jobRunner?.Post(action, priority);
}
}
}

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

@ -37,6 +37,11 @@ namespace Perspex.Threading
() => _timerJobRunner.Post(tick, DispatcherPriority.Normal));
public void Signal() => _evnt.Set();
public bool CheckForLoopThread()
{
//TODO: Actually perform check
return true;
}
public event Action Signaled;
}

4
src/Windows/Perspex.Win32/Win32Platform.cs

@ -21,6 +21,7 @@ namespace Perspex.Win32
public class Win32Platform : IPlatformThreadingInterface, IPlatformSettings
{
private static readonly Win32Platform s_instance = new Win32Platform();
private static Thread _uiThread;
private UnmanagedMethods.WndProc _wndProcDelegate;
@ -52,6 +53,7 @@ namespace Perspex.Win32
.Bind<ISystemDialogImpl>().ToSingleton<SystemDialogImpl>();
SharedPlatform.Register();
_uiThread = Thread.CurrentThread;
}
public static void Initialize()
@ -124,6 +126,8 @@ namespace Perspex.Win32
new IntPtr(SignalL));
}
public bool CheckForLoopThread() => _uiThread == Thread.CurrentThread;
public event Action Signaled;
[SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Using Win32 naming for consistency.")]

Loading…
Cancel
Save