Search code examples
uwpmulti-windowvirtual-desktop

open secondary view on current virtual desktop in uwp apps


Microsoft's documentation on virtual desktops says:

To support this concept, applications should avoid automatically switching the user from one virtual desktop to another. Only the user should instigate that change. In order to support this, newly created windows should appear on the currently active virtual desktop. In addition, if an application can reuse currently active windows, it should only reuse windows if they are on the currently active virtual desktop. Otherwise, a new window should be created.

and I totally agree and would like to see my UWP app doing exactly that. However, after starting the app on virtual desktop A and switching to virtual desktop B, opening the app again (be it via the startmenu or a notification) throws me back to virtual desktop A before OnLaunched is executed, and my new window thus also resides on A.

Other uwp apps like the calculator can properly spawn new windows on other virtual desktops, but how?


Solution

  • The problem is that the ApplicationViewSwitcher.TryShowAsStandaloneAsync methods always align the new window with the original window, even if the original window is on a different virtual desktop.

    To circumvent this you have to disable the system's default view handling. When you create the root frame's content the first time, disable the default handling:

    ApplicationViewSwitcher.DisableShowingMainViewOnActivation();
    ApplicationViewSwitcher.DisableSystemViewActivationPolicy();
    

    When you create your new view, don't use ApplicationViewSwitcher.TryShowAsStandaloneAsync to display the new view's window. Use the ViewSwitcher from the LaunchActivatedEventArgs instead:

    CoreApplicationView newView = CoreApplication.CreateNewView();
    int newViewId = 0;
    await newView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
    {
        Frame frame = new Frame();
        frame.Navigate(typeof(MainPage), e.Arguments);
        Window.Current.Content = frame;
        Window.Current.Activate();
        var currView = ApplicationView.GetForCurrentView();
        currView.Consolidated += CurrView_Consolidated;
        newViewId = currView.Id;
        await e.ViewSwitcher.ShowAsStandaloneAsync(newViewId);
    });
    

    Note: ViewSwitcher.ShowAsStandaloneAsync must be called on the new view's UI thread, unlike ApplicationViewSwitcher.TryShowAsStandaloneAsync!