diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000000..99d196ace7
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,23 @@
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": ".NET Core Launch (console)",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "build",
+ "program": "${workspaceRoot}\\samples\\ControlCatalog.NetCore\\bin\\Debug\\netcoreapp1.1\\ControlCatalog.NetCore.dll",
+ "args": [],
+ "cwd": "${workspaceRoot}\\samples\\ControlCatalog.NetCore",
+ "console": "internalConsole",
+ "stopAtEntry": false,
+ "internalConsoleOptions": "openOnSessionStart"
+ },
+ {
+ "name": ".NET Core Attach",
+ "type": "coreclr",
+ "request": "attach",
+ "processId": "${command:pickProcess}"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 0000000000..27f8776c5f
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,16 @@
+{
+ "version": "0.1.0",
+ "command": "dotnet",
+ "isShellCommand": true,
+ "args": [],
+ "tasks": [
+ {
+ "taskName": "build",
+ "args": [
+ "${workspaceRoot}\\samples\\ControlCatalog.NetCore\\ControlCatalog.NetCore.csproj"
+ ],
+ "isBuildCommand": true,
+ "problemMatcher": "$msCompile"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Avalonia.v3.ncrunchsolution b/Avalonia.v3.ncrunchsolution
index c2c454eae1..1b5b0c8930 100644
--- a/Avalonia.v3.ncrunchsolution
+++ b/Avalonia.v3.ncrunchsolution
@@ -3,7 +3,7 @@
tests\TestFiles\**.*
- False
+ True
.ncrunch
True
diff --git a/src/Avalonia.Base/IPriorityValueOwner.cs b/src/Avalonia.Base/IPriorityValueOwner.cs
index 57f98c0717..aeec720920 100644
--- a/src/Avalonia.Base/IPriorityValueOwner.cs
+++ b/src/Avalonia.Base/IPriorityValueOwner.cs
@@ -25,5 +25,10 @@ namespace Avalonia
/// The source of the change.
/// The notification.
void BindingNotificationReceived(PriorityValue sender, BindingNotification notification);
+
+ ///
+ /// Ensures that the current thread is the UI thread.
+ ///
+ void VerifyAccess();
}
}
diff --git a/src/Avalonia.Base/PriorityBindingEntry.cs b/src/Avalonia.Base/PriorityBindingEntry.cs
index 25b7bede7e..eb7cf5414c 100644
--- a/src/Avalonia.Base/PriorityBindingEntry.cs
+++ b/src/Avalonia.Base/PriorityBindingEntry.cs
@@ -92,6 +92,8 @@ namespace Avalonia
private void ValueChanged(object value)
{
+ _owner.Owner.Owner?.VerifyAccess();
+
var notification = value as BindingNotification;
if (notification != null)
diff --git a/src/Avalonia.Base/PriorityLevel.cs b/src/Avalonia.Base/PriorityLevel.cs
index 122a6df821..b25247deaf 100644
--- a/src/Avalonia.Base/PriorityLevel.cs
+++ b/src/Avalonia.Base/PriorityLevel.cs
@@ -33,7 +33,6 @@ namespace Avalonia
///
internal class PriorityLevel
{
- private PriorityValue _owner;
private object _directValue;
private int _nextIndex;
@@ -48,13 +47,18 @@ namespace Avalonia
{
Contract.Requires(owner != null);
- _owner = owner;
+ Owner = owner;
Priority = priority;
Value = _directValue = AvaloniaProperty.UnsetValue;
ActiveBindingIndex = -1;
Bindings = new LinkedList();
}
+ ///
+ /// Gets the owner of the level.
+ ///
+ public PriorityValue Owner { get; }
+
///
/// Gets the priority of this level.
///
@@ -73,7 +77,7 @@ namespace Avalonia
set
{
Value = _directValue = value;
- _owner.LevelValueChanged(this);
+ Owner.LevelValueChanged(this);
}
}
@@ -131,7 +135,7 @@ namespace Avalonia
{
Value = entry.Value;
ActiveBindingIndex = entry.Index;
- _owner.LevelValueChanged(this);
+ Owner.LevelValueChanged(this);
}
else
{
@@ -161,7 +165,7 @@ namespace Avalonia
/// The error.
public void Error(PriorityBindingEntry entry, BindingNotification error)
{
- _owner.LevelError(this, error);
+ Owner.LevelError(this, error);
}
///
@@ -175,14 +179,14 @@ namespace Avalonia
{
Value = binding.Value;
ActiveBindingIndex = binding.Index;
- _owner.LevelValueChanged(this);
+ Owner.LevelValueChanged(this);
return;
}
}
Value = DirectValue;
ActiveBindingIndex = -1;
- _owner.LevelValueChanged(this);
+ Owner.LevelValueChanged(this);
}
}
}
diff --git a/src/Avalonia.Base/PriorityValue.cs b/src/Avalonia.Base/PriorityValue.cs
index 3f4b405de9..57e2854014 100644
--- a/src/Avalonia.Base/PriorityValue.cs
+++ b/src/Avalonia.Base/PriorityValue.cs
@@ -26,7 +26,6 @@ namespace Avalonia
///
internal class PriorityValue
{
- private readonly IPriorityValueOwner _owner;
private readonly Type _valueType;
private readonly SingleOrDictionary _levels = new SingleOrDictionary();
private object _value;
@@ -45,7 +44,7 @@ namespace Avalonia
Type valueType,
Func
internal class JobRunner
{
- private readonly IPlatformThreadingInterface _platform;
private readonly Queue _queue = new Queue();
+ private IPlatformThreadingInterface _platform;
public JobRunner(IPlatformThreadingInterface platform)
{
@@ -82,6 +81,14 @@ namespace Avalonia.Threading
AddJob(new Job(action, priority, true));
}
+ ///
+ /// Allows unit tests to change the platform threading interface.
+ ///
+ internal void UpdateServices()
+ {
+ _platform = AvaloniaLocator.Current.GetService();
+ }
+
private void AddJob(Job job)
{
var needWake = false;
@@ -91,7 +98,7 @@ namespace Avalonia.Threading
_queue.Enqueue(job);
}
if (needWake)
- _platform.Signal();
+ _platform?.Signal();
}
///
diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs
index 5e286305d2..cd8184b140 100644
--- a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs
+++ b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs
@@ -365,7 +365,7 @@ namespace Avalonia.Base.UnitTests
}
[Fact]
- public async void Bind_With_Scheduler_Executes_On_Scheduler()
+ public async Task Bind_With_Scheduler_Executes_On_Scheduler()
{
var target = new Class1();
var source = new Subject