Correct way to get the CoreDispatcher in a Windows Store app

43,786

Solution 1

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.

Solution 2

For anyone using C++/CX

Windows::ApplicationModel::Core::CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
    CoreDispatcherPriority::Normal,
    ref new Windows::UI::Core::DispatchedHandler([this]()
{
    // do stuff
}));

Solution 3

await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
            CoreDispatcherPriority.Normal,
            () => { // your code should be here});

Solution 4

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.

Share:
43,786

Related videos on Youtube

lysergic-acid
Author by

lysergic-acid

Software Engineer, Game Developer, Cat Owner Blogging @ http://www.tallior.com Check out my gigs @ http://www.fiverr.com/lysergide

Updated on July 08, 2022

Comments

  • lysergic-acid
    lysergic-acid almost 2 years

    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?

    • Nate Diamond
      Nate Diamond almost 11 years
      Both are kind of correct, but it will be null if you're not accessing it from something that already has access to the Dispatcher. If you want to use it in, say, a ViewModel or Controller, then you'll need to store off the Dispatcher, generally as a static Property in your App.xaml.cs or IOC controller, and set it from the first page that you have load.
  • Robert Oschler
    Robert Oschler about 10 years
    I tried this but when I trace the code, the delegate code is still executing on a Worker thread and not the "Main Thread".
  • Illidan
    Illidan about 10 years
    Please note that (at least in Windows 8.1) DispatcherPriority is now CoreDispatcherPriority
  • Yury Schkatula
    Yury Schkatula over 6 years
    This would work as long as we have single ASTA (application single-threaded apartment). In case we introduce "sharing target" feature, there are multiple ASTAs (each one with its own dispatcher). And then CoreApplication.MainView can be null (because its ASTA is not initialized yet). Be aware!
  • sjb-sjb
    sjb-sjb over 6 years
    I have seen CoreApplication.MainView cause my program to hang when called from a non-UI thread. I had to stash the CoreApplication.MainView.CoreWindow.Dispatcher at startup in order to access it later.
  • Richard Chambers
    Richard Chambers almost 6 years
    "For authoring and consuming Windows Runtime APIs using C++, there is C++/WinRT. This is Microsoft's recommended replacement for the Windows Runtime C++ Template Library (WRL) and C++/CX." C++/WinRT
  • Gregory Bologna
    Gregory Bologna over 2 years
    This worked for me in UWP app as long as I used discard operator. _ = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => someMethod("abc"));
  • MAXE
    MAXE over 2 years
    @GregoryBologna interesting...but I think yours is just a syntax issue...any lamba expression can be used in {} form: docs.microsoft.com/en-us/dotnet/csharp/language-reference/…