Windows 8.1 enables powerful multitasking by allowing a user to split her screen to see several different Windows Store apps simultaneously. There are times, though, when it’s valuable to have multiple windows of the same app on the screen. For example, when developing websites it’s convenient to have side-by-side browser windows for a code editor, a debugger, and documentation.
Windows 8.1 allows a single app to show more than one window so that users can quickly access two different parts of the app at the same time. This unlocks new scenarios such as comparing multiple documents simultaneously or composing a document while referencing other materials from the same app. Apps can even leverage multiple displays by showing content on one display and something else on another display. As a developer, you can surface this capability in your app to make your apps even more powerful and efficient.
If your app has multiple independent functions, like viewing two unrelated pieces of content, you can help your users be more productive by allowing each function in a separate window. The user can then move, size, show or hide each window alongside other apps to easily complete her workflow. If the user has more than one display attached to their device, the window can also be moved to any of these displays.
Mail, Internet Explorer, and Reader are some of the first apps to support multiple windows. Mail is a great example of how multiple windows should work. Mail starts by offering an elegant and efficient experience in a single window. By default, whenever the user starts a new message or opens an existing email, Mail shows that item in the same window as the inbox. Such behavior makes navigation inside Mail fast and keeps window management simple since there is only one window. However, users may find themselves switching back to a particular message they’re writing or reading.
Mail makes users more powerful by letting them optionally open a particular message in a secondary window. This new Mail window behaves as if it were a separate app—the user can put the main Mail window on screen next to the message without losing sight of the important email. Likewise, system switching surfaces, like Alt + Tab and the list of recently used apps make it easy to get back to this message when it leaves the screen.
When a message is opened in a new window, that window contains all the functionality necessary to act on the message. If the user needs more space to read or write the email or to use another app alongside it, the user can move the inbox window off screen and still view or reply to the mail. All the controls necessary to format, edit, and send the email are available in the window.
It’s possible for the user to close a window containing a message by dragging the window from the top to bottom of the screen. The window can also fall out of the list of recently used apps as the user navigates to a set of other apps. Mail, though, does save the email and lets the user navigate back to it from the inbox and even recreate the new window. Likewise, the main Mail window containing the inbox can also be closed or leave the list of recently used apps. The Mail app always allows the user to get back to the inbox from inside a secondary window by simply pressing the back button in the window. Tapping the Mail tile in Start always brings back the most recently used window of the app, so the user can eventually get back to the inbox even if she doesn’t have access to any particular Mail window.
Mail’s design for secondary windows demonstrates several principles:
- Keep the user in control: Rely on an explicit user action to trigger the creation of a new window instead of overwhelming users with the automatic creation of several windows.
- Build a great single-window experience and enhance it with secondary windows: Users should be able to accomplish all the scenarios your app targets inside your main, single window. Add secondary windows only for tasks that that involve using two separate parts of your app at the same time.
- Make secondary windows purposeful and complete: A secondary window should contain some task that can be completed independently of any other window.
- Allow the user to get back to the contents of each window: Users can lose access to windows when they fall out of the list of recently used apps. Make sure their important data is always preserved and allow them to easily recreate the separate window if they wish.
Building an app with multiple windows
Having identified the scenarios where your app allows the use of secondary windows, you can build the functionality in a few steps. The MultipleViews sample demonstrates use of the API.
Creating a new view
Start by creating a new view using your framework’s respective method.
1 <span>var</span> newView = MSApp.createNewView(<span>"ms-appx:///html/secondaryView.html"</span>);
1 CoreApplicationView newView = CoreApplication.CreateNewView();
The first view created when your app starts up (called the main view) is special. When an app is activated for a contract like File or Protocol Launch, the main view’s window is presented to the user unless ApplicationViewSwitcher.DisableShowingMainViewOnActivation is called during process startup (ApplicationViewSwitcher is the main class for managing the behavior of multiple windows; we talk about this later). All activation events (even if DisableShowingMainViewOnActivation is called) are delivered on the main view’s thread. If this view’s window closes or the thread dies for any other reason, the app is terminated.
Populating a new window
1 newView.postMessage( myState: <span>'My important state'</span>, thisOrigin);
1 await newView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =><br /><br /> <span>var</span> frame = <span>new</span> Frame();<br /> frame.Navigate(<span>typeof</span>(SecondaryViewPage), <span>null</span>);<br /> Window.Current.Content = frame;<br />); <br />
In the C# code, note the call to RunAsync. Because the lambda function interacts with the new window’s UI, it must be called on that view’s thread.
Displaying the new window
After a new view has been created, show the new window using ApplicationViewSwitcher.TryShowAsStandaloneAsync. All ApplicationViewSwitcher APIs accept view IDs, which are integers that uniquely identify each of the views in your app. Retrieve the view ID using ApplicationView.Id or ApplicationView.GetApplicationViewIdForWindow. Additionally, the object returned from MSApp.createNewView also has a viewId property containing the new view’s ID. The complete code to create and show a new window is below:
1 <span>var</span> newView = MSApp.createNewView(<span>"ms-appx:///html/secondaryView.html"</span>);<br />newView.postMessage( myState: <span>'My important state'</span> , thisOrigin);<br />Windows.UI.ViewManagement.ApplicationViewSwitcher.tryShowAsStandaloneAsync(newView.viewId).done(<span>function</span> (viewShown) <br /><br />);<br />
1 <span>var</span> newView = CoreApplication.CreateNewView();<br /><span>int</span> newViewId = 0;<br />await newView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =><br /><br /> <span>var</span> frame = <span>new</span> Frame();<br /> frame.Navigate(<span>typeof</span>(SecondaryViewPage), <span>null</span>);<br /> Window.Current.Content = frame;<br /><br /> newViewId = ApplicationView.GetForCurrentView().Id;<br />);<br /><span>bool</span> viewShown = await ApplicationViewSwitcher.TryShowAsStandaloneAsync(newViewId);<br />
You’ll notice that TryShowAsStandloneAsync’s result is a Boolean, which indicates if the specified view was actually presented to the user. Your app may show a new window only under certain circumstances, principally being that the calling thread’s window has keyboard focus. In addition, this API behaves the same whether or not a given window has already been presented to the user. So, when users invoke “Open in new window” on an item that has already been shown in a separate window, you can use this API to bring that window on screen again.
Switching which window is on screen
Your app should allow the user to get to any content in the app from the current window. Sometimes that might require your app to switch which window is presented to the user. For example, Mail’s secondary windows have a back button that, when pressed, shows the main Mail window. ApplicationViewSwitcher.SwitchAsync accomplishes this. Simply call it from the thread of the window you’re switching from, passing in the view ID of the window you’re switching to.
1 await ApplicationViewSwitcher.SwitchAsync(viewIdToShow);
Note that this API behaves the same whether or not a given window has been shown to the user through TryShowAsStandaloneAsync.
Closing an unused window
After you’ve shown a window to the user, it remains in the list of recently used apps until the user launches enough other apps for it to fall out of the list. The Consolidated event is fired on the thread of the window that was removed from the list, provided that the app has at least one more window remaining in the list. Because each window consumes memory, it’s a good idea to close the window when you receive the event. Do not, though, close the main view’s window, as this will cause your app to terminate.
1 Windows.UI.ViewManagement.ApplicationView.getForCurrentView().addEventListener(<span>"consolidated"</span>, viewConsolidated, <span>false</span>);<br /><br /><span>function</span> viewConsolidated(e) <br /> <span>if</span> (!isMainView) <br /> window.close();<br /> <br />}<br />
1 ApplicationView.GetForCurrentView().Consolidated += ViewConsolidated;<br /><br /><span>void</span> ViewConsolidated(ApplicationView sender, ApplicationViewConsolidatedEventArgs e)<br /><br /> <span>if</span> (!CoreApplication.GetCurrentView().IsMain)<br /> <br /> Window.Current.Close();<br /> <br />}<br />
If you’d like to remove a window from the screen on behalf of the user, you can do so using SwitchAsync. Mail does this, for example, when sending or deleting the message contained in a secondary window. Note that it’s best practice, when closing a window, to replace it with another window (usually the main view of the app) so that the user can continue working in your app.
1 Windows.UI.ViewManagement.ApplicationViewSwitcher.switchAsync(<br /> replacementViewId, <br /> viewIdToClose,<br /> Windows.UI.ViewManagement.ApplicationViewSwitchingOptions.consolidateViews).done();<br />
1 await ApplicationViewSwitcher.SwitchAsync(<br /> replacementViewId, <br /> viewIdToClose,<br /> ApplicationViewSwitchingOptions.ConsolidateViews);<br />
Showing a window on another screen
Your app may also show a window on another display. For example, a game might keep the heads-up display on the primary display while the action appears on a TV or projector. A presentation viewer might show a slide on a projector, while the main device displays notes for the slide. The ProjectionManager class allows the app to place windows on more than just the primary display, and takes care of enabling projection on the display itself. This API is functionally similar to ApplicationViewSwitcher.
The steps for showing a window on a secondary display are the same as those presented above, with a few differences:
- Prior to creating a window, check if secondary display is available using ProjectionManager.ProjectionDisplayAvailable and ProjectionManager.ProjectionDisplayAvailableChanged
- After creating a window, show it on a secondary display by calling ProjectionManager.StartProjectingAsync instead of ApplicationViewSwitcher.TryShowAsStandaloneAsync
- To remove a window from a secondary display, call ProjectionManager.StopProjectingAsync instead of ApplicationViewSwitcher.SwitchAsync
See the Projection sample for more details.
Windows 8.1 allows your app to show two or more different parts of your app at the same time. This can make multi-tasking using your app an effortless, efficient experience for users.
If you’d like to learn more, check out these materials on MSDN:
- Multiple views sample
- Projection sample
- ApplicationViewSwitcher documentation
- ProjectionManager documentation
– Chaitanya Sareen, Principal Program Manager Lead, Windows