In .NET, Windows 8 and Windows Phone 7 I have code similar to this:
public static void InvokeIfRequired(this Dispatcher dispatcher, Action action)
{
if (dispatcher.CheckAccess())
{
action();
}
else
{
dispatcher.Invoke(action);
}
}
How would I do something in the portable class library? It would be nice to have one platform agnostic implementation of this. My idea is to use the TPL which is not available in WP7 but definitely will be soon.
// PortableDispatcher must be created on the UI thread and then made accessible
// maybe as a property in my ViewModel base class.
public class PortableDispatcher
{
private TaskScheduler taskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
public void Invoke(Action action)
{
if (Alread on UI thread. How would I do this.)
{
action();
}
Task.Factory.StartNew(
action,
CancellationToken.None,
TaskCreationOptions.None,
taskScheduler);
}
}
The only thing I'm unsure about is what the performance implications of this would be. Perhaps I'll do some tests.
You can use SynchronizationContext.Post or Send method. It is portable, and when you use a UI framework with a dispatcher then the current synchronization context will delegate the work to the Dispatcher.
Specifically, you can use the following code:
void InvokeIfRequired(this SynchroniationContext context, Action action)
{
if (SynchroniationContext.Current == context)
{
action();
}
else
{
context.Send(action) // send = synchronously
// context.Post(action) - post is asynchronous.
}
}
With the advent of the TPL. I came up with a slightly improved version of the accepted answer which returns a task and can be await'ed using the new async and await keywords.
public Task RunAsync(Action action)
{
TaskCompletionSource<object> taskCompletionSource = new TaskCompletionSource<object>();
if (this.synchronizationContext == SynchronizationContext.Current)
{
try
{
action();
taskCompletionSource.SetResult(null);
}
catch (Exception exception)
{
taskCompletionSource.SetException(exception);
}
}
else
{
// Run the action asyncronously. The Send method can be used to run syncronously.
this.synchronizationContext.Post(
(obj) =>
{
try
{
action();
taskCompletionSource.SetResult(null);
}
catch (Exception exception)
{
taskCompletionSource.SetException(exception);
}
},
null);
}
return taskCompletionSource.Task;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With