Execute: Dispatching to the UI thread - canton7/Stylet GitHub Wiki
Summary
Execute
is a little static helper, which makes it easier to dispatch delegates to be run on the UI thread. It wraps Application.Current.Dispatcher
, and provides methods to make it easier and terser to use.
It also provides a helper property, Execute.InDesignMode
. This is true if and only if the Visual Studio or Expression Blend designer is active, and code is being executed to supply dummy data for design-time display.
A high-level summary of the methods it offers is given in the table below, with more in-depth explanations given after.
Method | Inline if possible | Waits for Completion |
---|---|---|
Execute.OnUIThread | ✔ | ✘ |
Execute.OnUIThreadSync | ✔ | ✔ (Blocks) |
Execute.OnUIThreadAsync | ✔ | ✔ (Task) |
Execute.PostToUIThread | ✘ | ✘ |
Execute.PostToUIThreadAsync | ✘ | ✔ (Task) |
Inline if possible: The method will check if the current thread is the UI thread. If it is, the delegate will be run synchronously. If it isn't, then it will be dispatched to the UI thread in some form.
Waits for completion: Either blocks until the delegate has finished executing, or returns a Task which completes when the delegate has finished executing.
Details
Execute.OnUIThread
Checks to see whether the current thread is the UI thead. If it is, the delegate will be run synchronously. If it is not, the delegate will be dispatched to the UI thread, to be run at some point in the future. In this case, Execute.OnUIThread
will not wait for the delegate to complete.
This mirrors the traditional pattern of:
public static void InvokeIfRequired(Action action)
{
if (Application.Current.Dispatcher.CheckAccess())
action();
else
Application.Current.Dispatcher.BeginInvoke(action);
}
Execute.OnUIThreadSync
Checks to see whether the current thread is the UI thread. If it is, then it will run the delegate synchronously. If it is not, then it will dispatch the delegate to be run on the UI thread, and block until it has finished executing.
It is therefore very similar to Execute.OnUIThread
, except that it will only return after the delegate has finished executing.
Execute.OnUIThreadAsync
Checks to see whether the current thread is the UI thread. If it is, then it will run the delegate synchronously, and return a completed Task. If it is not, then it will dispatch the delegate to be run on the UI thread at some point in the future, and return a Task which completes when the delegate has finished executing.
It is therefore effectively the async version of Execute.OnUIThreadSync
.
Execute.PostToUIThread
Regardless of whether the current thread is the UI thread, will post the delegate to be run on the UI thread at some point in the future.
Execute.PostToUIThreadAsync
Regardless of whether the current thread is the UI thread, will post the delegate to be run on the UI thread at some point in the future, and returns a Task which completes when the delegate has finished executing.
BEWARE you must never do something like Execute.PostToUIThreadAsync(() => something(foo)).Wait()
. If you do that from the UI thread, you will cause a deadlock. This approach does not make sense with the Execute.PostXXX
methods - use Execute.OnUIThreadSync
or Execute.OnUIThreadAsync
instead.
Advanced: Unit Testing
The Dispatcher
Execute
actually has a level of abstraction from Application.Current.Dispatcher
.
Execute.Dispatcher
is a static property of type IDispatcher
, and is used by Execute
to dispatch delegates.
This property can never be null, and defaults to an IDispatcher
implementation which executes everything synchronously. It is then overridden in BootstrapperBase
to be a wrapper around Application.Current.Dispatcher
.
This behaviour means that methods using one of the Execute
methods can be unit-tested, or used at design-time.
In unit testing, all Execute
methods will run their delegate synchronously (since a Dispatcher isn't available).
If you need to, you can also set Execute.Dispatcher
to a custom IDispatcher
implementation for your unit tests.
Design Mode
Execute.InDesignMode
is also settable, and this will override the "actual" value.
It is anticipated that you will almost never need to actually do this, but sometimes it's unavailable in order to unit test queer little edge cases (there are a couple of such cases in Stylet).