What is “multiple view” in UWP?

In UWP, your “main” application can open a new – separated – view.

Here is a link from the Microsoft website.

When should you use multiple views?

In many cases it is useful to be able to open multiple views:

– An email app that lets users view a list of received messages while composing a new email
– An address book app that lets users compare contact info for multiple people side-by-side
– A music player app that lets users see what’s playing while browsing through a list of other available music
– A note-taking app that lets users copy information from one page of notes to another
– A reading app that lets users open several articles for reading later, after an opportunity to peruse all high-level headlines

How to run on the UI Thread?

If you have only one view you can use the following code to return to the UI Thread and execute some code.

await Window.Current.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
    //UI code here
});
Code language: C# (cs)

I prefer to use the extension method from the UWP toolkit.

await Window.Current.Dispatcher.AwaitableRunAsync(() =>
{
    //UI code here
});

await DispatcherHelper.ExecuteOnUIThreadAsync(() =>
{
    // Code to execute on main window's UI thread
});
Code language: C# (cs)

The reason why is explained here. The RunAsync schedules the work on the UI thread and returns control to the caller immediately. Here is an example of wrong utilisation.

//From Microsoft
//DO NOT USE THIS CODE.

await dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
   await signInDialog.ShowAsync(); 
});

// Execution continues here before the call to ShowAsync completes.
Code language: C# (cs)

How to run on UI Thread when I create a new View?

When you play with multiple Views you can’t use the previous code because you working with multiple UI Thread. You ignore on which one you one to go back. The exception you will get, if you are on the wrong thread will be something like this “The application called an interface that was marshalled for a different thread”.

I found nothing about this problem on Google. So , I implemented my own AwaitableRunAsync supporting MuliView. May be it is not the best way to do, but it’s working very well on a big UWP Project.

Firstly, you need class where you keep the “thread identifier”. We will use the windowId of the View.

    public class DispatcherManager
    {
        public int CurrentWindowId { get; set; }

        public DispatcherManager(int windowId)
        {
            CurrentWindowId = windowId;
        }

...
Code language: C# (cs)

This is how to get the window Id of the current view and instantiate the DispatcherManager. (ApplicationView)

new DisptacherManager(ApplicationView.GetForCurrentView().Id)
Code language: C# (cs)

There is only two method in the DispatcherManager class. It allow you to choose between Func<Task> and Action..

public async Task AwaitableRunAsync(Action function)
{
    foreach (var iteratingview in CoreApplication.Views)
    {
        await iteratingview.Dispatcher.AwaitableRunAsync(() =>
        {
            if (ApplicationView.GetForCurrentView().Id == CurrentWindowId)
            {
                function.Invoke();
            }
        }, CoreDispatcherPriority.Normal);
    }
}

public async Task AwaitableRunAsync(Func<Task> function)
{
    foreach (var iteratingview in CoreApplication.Views)
    {
        await iteratingview.Dispatcher.AwaitableRunAsync(async () =>
        {
            if (ApplicationView.GetForCurrentView().Id == CurrentWindowId)
            {
                await function.Invoke();
            }
        }, CoreDispatcherPriority.Normal);
    }
}
Code language: C# (cs)

As you can see It iterate all the views via CoreApplication.Views Secondly, You must go back the UI Thread of the iterated view. You can do that via the await iteratingview.Dispatcher.AwaitableRunAsync. Finally, you are able to invoke you function or action on the UI Thread.