Add Execute.PostToUIThreadAsync

This commit is contained in:
Antony Male 2014-07-26 11:51:46 +01:00
parent a7a63d5ae1
commit 642a038488
2 changed files with 122 additions and 23 deletions

View File

@ -84,6 +84,7 @@ namespace Stylet
/// <summary>
/// Dispatches the given action to be run on the UI thread asynchronously, even if the current thread is the UI thread
/// </summary>
/// <param name="action">Action to run on the UI thread</param>
public static void PostToUIThread(Action action)
{
EnsureDispatcher();
@ -93,9 +94,29 @@ namespace Stylet
action();
}
/// <summary>
/// Dispatches the given action to be run on the UI thread asynchronously, and returns a task which completes when the action completes, even if the current thread is the UI thread
/// </summary>
/// <param name="action">Action to run on the UI thread</param>
/// <returns>Task which completes when the action has been run</returns>
public static Task PostToUIThreadAsync(Action action)
{
EnsureDispatcher();
if (!TestExecuteSynchronously)
{
return PostOnUIThreadInternalAsync(action);
}
else
{
action();
return Task.FromResult(false);
}
}
/// <summary>
/// Dispatches the given action to be run on the UI thread asynchronously, or runs it synchronously if the current thread is the UI thread
/// </summary>
/// <param name="action">Action to run on the UI thread</param>
public static void OnUIThread(Action action)
{
EnsureDispatcher();
@ -108,6 +129,7 @@ namespace Stylet
/// <summary>
/// Dispatches the given action to be run on the UI thread and blocks until it completes, or runs it synchronously if the current thread is the UI thread
/// </summary>
/// <param name="action">Action to run on the UI thread</param>
public static void OnUIThreadSync(Action action)
{
EnsureDispatcher();
@ -138,25 +160,14 @@ namespace Stylet
/// <summary>
/// Dispatches the given action to be run on the UI thread and returns a task that completes when the action completes, or runs it synchronously if the current thread is the UI thread
/// </summary>
/// <param name="action">Action to run on the UI thread</param>
/// <returns>Task which completes when the action has been run</returns>
public static Task OnUIThreadAsync(Action action)
{
EnsureDispatcher();
if (!TestExecuteSynchronously && !Dispatcher.IsCurrent)
{
var tcs = new TaskCompletionSource<object>();
Dispatcher.Post(() =>
{
try
{
action();
tcs.SetResult(null);
}
catch (Exception e)
{
tcs.SetException(e);
}
});
return tcs.Task;
return PostOnUIThreadInternalAsync(action);
}
else
{
@ -165,6 +176,24 @@ namespace Stylet
}
}
private static Task PostOnUIThreadInternalAsync(Action action)
{
var tcs = new TaskCompletionSource<object>();
Dispatcher.Post(() =>
{
try
{
action();
tcs.SetResult(null);
}
catch (Exception e)
{
tcs.SetException(e);
}
});
return tcs.Task;
}
/// <summary>
/// Determing if we're currently running in design mode
/// </summary>

View File

@ -21,7 +21,7 @@ namespace StyletUnitTests
}
[Test]
public void OnUIThreadExecutesUsingDispatcher()
public void OnUIThreadSyncExecutesUsingDispatcher()
{
var sync = new Mock<IDispatcher>();
Execute.Dispatcher = sync.Object;
@ -38,7 +38,22 @@ namespace StyletUnitTests
}
[Test]
public void BeginOnUIThreadExecutesUsingDispatcher()
public void OnUIThreadSyncExecutesSynchronouslyIfDispatcherIsCurrent()
{
var sync = new Mock<IDispatcher>();
Execute.Dispatcher = sync.Object;
sync.SetupGet(x => x.IsCurrent).Returns(true);
bool actionCalled = false;
Execute.OnUIThreadSync(() => actionCalled = true);
Assert.IsTrue(actionCalled);
sync.Verify(x => x.Send(It.IsAny<Action>()), Times.Never);
}
[Test]
public void PostToUIThreadExecutesUsingDispatcher()
{
var sync = new Mock<IDispatcher>();
Execute.Dispatcher = sync.Object;
@ -55,7 +70,26 @@ namespace StyletUnitTests
}
[Test]
public void BeginOnUIThreadOrSynchronousExecutesUsingDispatcherIfNotCurrent()
public void PostToUIThreadAsyncExecutesUsingDispatcher()
{
var sync = new Mock<IDispatcher>();
Execute.Dispatcher = sync.Object;
Action passedAction = null;
sync.Setup(x => x.Post(It.IsAny<Action>())).Callback((Action a) => passedAction = a);
bool actionCalled = false;
var task = Execute.PostToUIThreadAsync(() => actionCalled = true);
Assert.IsFalse(task.IsCompleted);
Assert.IsFalse(actionCalled);
passedAction();
Assert.IsTrue(actionCalled);
Assert.IsTrue(task.IsCompleted);
}
[Test]
public void OnUIThreadExecutesUsingDispatcherIfNotCurrent()
{
var sync = new Mock<IDispatcher>();
Execute.Dispatcher = sync.Object;
@ -91,7 +125,7 @@ namespace StyletUnitTests
}
[Test]
public void OnUIThreadPropagatesException()
public void OnUIThreadSyncPropagatesException()
{
var sync = new Mock<IDispatcher>();
Execute.Dispatcher = sync.Object;
@ -125,21 +159,45 @@ namespace StyletUnitTests
}
[Test]
public void ThrowsIfBeginOnUIThreadCalledWithNoDispatcher()
public void PostToUIThreadAsyncPrepagatesException()
{
var sync = new Mock<IDispatcher>();
Execute.Dispatcher = sync.Object;
Action passedAction = null;
sync.Setup(x => x.Post(It.IsAny<Action>())).Callback((Action a) => passedAction = a);
var ex = new Exception("test");
var task = Execute.PostToUIThreadAsync(() => { throw ex; });
passedAction();
Assert.IsTrue(task.IsFaulted);
Assert.AreEqual(ex, task.Exception.InnerExceptions[0]);
}
[Test]
public void ThrowsIfPostToUIThreadCalledWithNoDispatcher()
{
Execute.Dispatcher = null;
Assert.Throws<InvalidOperationException>(() => Execute.PostToUIThread(() => { }));
}
[Test]
public void ThrowsIfBeginOnUIThreadOrSynchronousCalledWithNoDispatcher()
public void ThrowsIfPostToUIThreadAsyncCalledWithNoDispatcher()
{
Execute.Dispatcher = null;
Assert.Throws<InvalidOperationException>(() => Execute.PostToUIThreadAsync(() => { }));
}
[Test]
public void ThrowsIfOnUIThreadCalledWithNoDispatcher()
{
Execute.Dispatcher = null;
Assert.Throws<InvalidOperationException>(() => Execute.OnUIThread(() => { }));
}
[Test]
public void ThrowsIfOnUIThreadCalledWithNoDispatcher()
public void ThrowsIfOnUIThreadSyncCalledWithNoDispatcher()
{
Execute.Dispatcher = null;
Assert.Throws<InvalidOperationException>(() => Execute.OnUIThreadSync(() => { }));
@ -153,7 +211,7 @@ namespace StyletUnitTests
}
[Test]
public void BeginOnUIThreadExecutesSynchronouslyIfTestExecuteSynchronouslySet()
public void PostToUIThreadExecutesSynchronouslyIfTestExecuteSynchronouslySet()
{
Execute.TestExecuteSynchronously = true;
@ -164,7 +222,19 @@ namespace StyletUnitTests
}
[Test]
public void OnUIThreadExecutesSynchronouslyIfTestExecuteSynchronouslySet()
public void PostToUIThreadAsyncExecutesSynchronouslyIfTestExecuteSynchronouslySet()
{
Execute.TestExecuteSynchronously = true;
Execute.Dispatcher = null;
bool called = false;
var task = Execute.PostToUIThreadAsync(() => called = true);
Assert.True(called);
Assert.True(task.IsCompleted);
}
[Test]
public void OnUIThreadSyncExecutesSynchronouslyIfTestExecuteSynchronouslySet()
{
Execute.TestExecuteSynchronously = true;