I'm building a Windows Store app, and I have some code that needs to be posted to the UI thread.
For that, i'd like to retrieve the CoreDispatcher and use it to post the code.
It seems that there are a few ways to do so:
// First way
Windows.ApplicationModel.Core.CoreApplication.GetCurrentView().CoreWindow.Dispatcher;
// Second way
Window.Current.Dispatcher;
I wonder which one is correct? or if both are equivalent?
This is the preferred way:
Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
// Your UI update code goes here!
});
The advantage this has is that it gets the main CoreApplicationView
and so is always available. More details here.
There are two alternatives which you could use.
First alternative
Windows.ApplicationModel.Core.CoreApplication.GetCurrentView().CoreWindow.Dispatcher
This gets the active view for the app, but this will give you null, if no views has been activated. More details here.
Second alternative
Window.Current.Dispatcher
This solution will not work when it's called from another thread as it returns null instead of the UI Dispatcher. More details here.
For anyone using C++/CX
Windows::ApplicationModel::Core::CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
CoreDispatcherPriority::Normal,
ref new Windows::UI::Core::DispatchedHandler([this]()
{
// do stuff
}));
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
CoreDispatcherPriority.Normal,
() => { // your code should be here});
Actually, I would propose something in the line of this:
return (Window.Current == null) ?
CoreApplication.MainView.CoreWindow.Dispatcher :
CoreApplication.GetCurrentView().CoreWindow.Dispatcher
That way, should you have openend another View/Window, you won't get the Dispatchers confused...
This little gem checks whether there is even a Window. If none, use the MainView's Dispatcher. If there is a view, use that one's Dispatcher.
While this is an old thread, I wanted to draw attention to a possible issue developers may run across which impacted me and made it extremely difficult to debug in large UWP apps. In my case, I refactored the following code from the suggestions above back in 2014 but would occasionally be plagued with the occasional app freezes that were random in nature.
public static class DispatcherHelper
{
public static Task RunOnUIThreadAsync(Action action)
{
return RunOnUIThreadAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, action);
}
public static async Task RunOnUIThreadAsync(Windows.UI.Core.CoreDispatcherPriority priority, Action action)
{
try
{
await returnDispatcher().RunAsync(priority, () =>
{
action();
});
}
catch (Exception ex)
{
var noawait = ExceptionHandler.HandleException(ex, false);
}
}
private static Windows.UI.Core.CoreDispatcher returnDispatcher()
{
return (Windows.UI.Xaml.Window.Current == null) ?
CoreApplication.MainView.CoreWindow.Dispatcher :
CoreApplication.GetCurrentView().CoreWindow.Dispatcher;
}
}
From the above, I had used a static class to allow the calling of the Dispatcher through-out the application - allowing for a single call. For 95% of the time, everything was fine even through QA regression but clients would report an issue every now and then. The solution was to include the call below, not using a static call in the actual pages.
await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
});
This is not the case when I need to ensure the UI Thread was called from App.xaml.cs or my Singleton NavigationService which handled pushing/popping on to the stack. The dispatcher apparently was losing track of which UI Thread was called, since each page has it's own UI thread, when the stack had a variety of Messages triggering from the MessageBus.
Hope this helps others that may be impacted and it is also where I think each platform would do a service to their developers by publishing a complete project covering the best practices.