diff --git a/build/Microsoft.CSharp.props b/build/Microsoft.CSharp.props
index d0fa63bc3e..4f738dd254 100644
--- a/build/Microsoft.CSharp.props
+++ b/build/Microsoft.CSharp.props
@@ -1,5 +1,5 @@
-
+
diff --git a/build/Microsoft.Reactive.Testing.props b/build/Microsoft.Reactive.Testing.props
index 5ee6df708e..777bc4bb53 100644
--- a/build/Microsoft.Reactive.Testing.props
+++ b/build/Microsoft.Reactive.Testing.props
@@ -1,5 +1,5 @@
-
+
diff --git a/build/ReactiveUI.props b/build/ReactiveUI.props
index 11afefa8ad..acdfdd215a 100644
--- a/build/ReactiveUI.props
+++ b/build/ReactiveUI.props
@@ -1,5 +1,5 @@
-
+
diff --git a/build/Rx.props b/build/Rx.props
index 7078e31195..f4affcacac 100644
--- a/build/Rx.props
+++ b/build/Rx.props
@@ -1,9 +1,9 @@
-
-
-
-
-
+
+
+
+
+
diff --git a/samples/ControlCatalog/Pages/RadioButtonPage.xaml b/samples/ControlCatalog/Pages/RadioButtonPage.xaml
index 0882817a9a..9525f6187e 100644
--- a/samples/ControlCatalog/Pages/RadioButtonPage.xaml
+++ b/samples/ControlCatalog/Pages/RadioButtonPage.xaml
@@ -22,6 +22,19 @@
Three States: Option 3
Disabled
+
+ Group A: Option 1
+ Group A: Disabled
+ Group B: Option 1
+ Group B: Option 3
+
+
+ Group A: Option 2
+ Group B: Option 2
+ Group B: Option 4
+
\ No newline at end of file
diff --git a/src/Avalonia.Base/Threading/Dispatcher.cs b/src/Avalonia.Base/Threading/Dispatcher.cs
index cf7acb3e8a..aa2a7a7a8e 100644
--- a/src/Avalonia.Base/Threading/Dispatcher.cs
+++ b/src/Avalonia.Base/Threading/Dispatcher.cs
@@ -69,7 +69,7 @@ namespace Avalonia.Threading
///
public void RunJobs()
{
- _jobRunner?.RunJobs(null);
+ _jobRunner.RunJobs(null);
}
///
@@ -82,14 +82,21 @@ namespace Avalonia.Threading
public Task InvokeAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal)
{
Contract.Requires(action != null);
- return _jobRunner?.InvokeAsync(action, priority);
+ return _jobRunner.InvokeAsync(action, priority);
+ }
+
+ ///
+ public Task InvokeAsync(Func function, DispatcherPriority priority = DispatcherPriority.Normal)
+ {
+ Contract.Requires(function != null);
+ return _jobRunner.InvokeAsync(function, priority);
}
///
public void Post(Action action, DispatcherPriority priority = DispatcherPriority.Normal)
{
Contract.Requires(action != null);
- _jobRunner?.Post(action, priority);
+ _jobRunner.Post(action, priority);
}
///
diff --git a/src/Avalonia.Base/Threading/IDispatcher.cs b/src/Avalonia.Base/Threading/IDispatcher.cs
index 4009dcdeab..1fdc9da5fe 100644
--- a/src/Avalonia.Base/Threading/IDispatcher.cs
+++ b/src/Avalonia.Base/Threading/IDispatcher.cs
@@ -28,12 +28,17 @@ namespace Avalonia.Threading
void Post(Action action, DispatcherPriority priority = DispatcherPriority.Normal);
///
- /// Post action that will be invoked on main thread
+ /// Posts an action that will be invoked on the dispatcher thread.
///
/// The method.
/// The priority with which to invoke the method.
- // TODO: The naming of this method is confusing: the Async suffix usually means return a task.
- // Remove this and rename InvokeTaskAsync as InvokeAsync. See #816.
Task InvokeAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal);
+
+ ///
+ /// Posts a function that will be invoked on the dispatcher thread.
+ ///
+ /// The method.
+ /// The priority with which to invoke the method.
+ Task InvokeAsync(Func function, DispatcherPriority priority = DispatcherPriority.Normal);
}
}
\ No newline at end of file
diff --git a/src/Avalonia.Base/Threading/JobRunner.cs b/src/Avalonia.Base/Threading/JobRunner.cs
index c2040a0982..b922370e84 100644
--- a/src/Avalonia.Base/Threading/JobRunner.cs
+++ b/src/Avalonia.Base/Threading/JobRunner.cs
@@ -14,32 +14,16 @@ namespace Avalonia.Threading
///
internal class JobRunner
{
-
-
private IPlatformThreadingInterface _platform;
- private Queue[] _queues = Enumerable.Range(0, (int) DispatcherPriority.MaxValue + 1)
- .Select(_ => new Queue()).ToArray();
+ private readonly Queue[] _queues = Enumerable.Range(0, (int) DispatcherPriority.MaxValue + 1)
+ .Select(_ => new Queue()).ToArray();
public JobRunner(IPlatformThreadingInterface platform)
{
_platform = platform;
}
- Job GetNextJob(DispatcherPriority minimumPriority)
- {
- for (int c = (int) DispatcherPriority.MaxValue; c >= (int) minimumPriority; c--)
- {
- var q = _queues[c];
- lock (q)
- {
- if (q.Count > 0)
- return q.Dequeue();
- }
- }
- return null;
- }
-
///
/// Runs continuations pushed on the loop.
///
@@ -52,24 +36,8 @@ namespace Avalonia.Threading
var job = GetNextJob(minimumPriority);
if (job == null)
return;
-
- if (job.TaskCompletionSource == null)
- {
- job.Action();
- }
- else
- {
- try
- {
- job.Action();
- job.TaskCompletionSource.SetResult(null);
- }
- catch (Exception e)
- {
- job.TaskCompletionSource.SetException(e);
- }
- }
+ job.Run();
}
}
@@ -83,7 +51,20 @@ namespace Avalonia.Threading
{
var job = new Job(action, priority, false);
AddJob(job);
- return job.TaskCompletionSource.Task;
+ return job.Task;
+ }
+
+ ///
+ /// Invokes a method on the main loop.
+ ///
+ /// The method.
+ /// The priority with which to invoke the method.
+ /// A task that can be used to track the method's execution.
+ public Task InvokeAsync(Func function, DispatcherPriority priority)
+ {
+ var job = new Job(function, priority);
+ AddJob(job);
+ return job.Task;
}
///
@@ -105,9 +86,9 @@ namespace Avalonia.Threading
_platform = AvaloniaLocator.Current.GetService();
}
- private void AddJob(Job job)
+ private void AddJob(IJob job)
{
- var needWake = false;
+ bool needWake;
var queue = _queues[(int) job.Priority];
lock (queue)
{
@@ -118,38 +99,129 @@ namespace Avalonia.Threading
_platform?.Signal(job.Priority);
}
+ private IJob GetNextJob(DispatcherPriority minimumPriority)
+ {
+ for (int c = (int) DispatcherPriority.MaxValue; c >= (int) minimumPriority; c--)
+ {
+ var q = _queues[c];
+ lock (q)
+ {
+ if (q.Count > 0)
+ return q.Dequeue();
+ }
+ }
+ return null;
+ }
+
+ private interface IJob
+ {
+ ///
+ /// Gets the job priority.
+ ///
+ DispatcherPriority Priority { get; }
+
+ ///
+ /// Runs the job.
+ ///
+ void Run();
+ }
+
///
/// A job to run.
///
- private class Job
+ private sealed class Job : IJob
{
+ ///
+ /// The method to call.
+ ///
+ private readonly Action _action;
+ ///
+ /// The task completion source.
+ ///
+ private readonly TaskCompletionSource