Be two places at once using multiple windows

Be two places at once using multiple windows

  • Comments 1
  • Likes

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.

Two windows of Internet Explorer on the screen
Two windows of Internet Explorer on the screen (from left to right: Internet Explorer, Bing Sports, Internet Explorer)

Design a great experience with multiple windows

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.

An e-mail message being displayed in a separate window of the Mail app
An e-mail message being displayed in a separate window of the Mail app

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.

Secondary Mail window displaying a reply with editing controls side by side with the Stocks app.
Secondary Mail window displaying a reply with editing controls side by side with the Stocks app.

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.

JavaScript:

var newView = MSApp.createNewView("ms-appx:///html/secondaryView.html");

C#:

CoreApplicationView newView = CoreApplication.CreateNewView();

These calls create a new thread and new window on that thread. This 1:1 pairing of thread and window is called a view (a new view is also created when your app fulfills Picker source and Share target contracts). Many objects you create, including all XAML UI and objects returned from GetForCurrentView, are tied to this thread and will throw exceptions when properties or methods are invoked from other threads. You may also need to synchronize access to objects shared among views. Communicate across threads using postMessage in JavaScript or CoreDispatcher.RunAsync in C#/C++/VB.

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

The JavaScript code above automatically loads the specified page inside the new window. You can deliver any extra state necessary to set up that window (e.g. the name of the document to load) using postMessage. You must take an extra step in C#/C++/VB to populate the window.

JavaScript:

newView.postMessage({ myState: 'My important state'}, thisOrigin);

C#:

await newView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
var frame = new Frame();
frame.Navigate(typeof(SecondaryViewPage), null);
Window.Current.Content = frame;
});

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:

Javascript:

var newView = MSApp.createNewView("ms-appx:///html/secondaryView.html");
newView.postMessage({ myState: 'My important state' }, thisOrigin);
Windows.UI.ViewManagement.ApplicationViewSwitcher.tryShowAsStandaloneAsync(newView.viewId).done(function (viewShown) {

});


C#:

var newView = CoreApplication.CreateNewView();
int newViewId = 0;
await newView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
var frame = new Frame();
frame.Navigate(typeof(SecondaryViewPage), null);
Window.Current.Content = frame;

newViewId = ApplicationView.GetForCurrentView().Id;
});
bool viewShown = await ApplicationViewSwitcher.TryShowAsStandaloneAsync(newViewId);

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.

JavaScript:

Windows.UI.ViewManagement.ApplicationViewSwitcher.SwitchAsync(viewIdToShow).done();

C#:

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.

JavaScript:

Windows.UI.ViewManagement.ApplicationView.getForCurrentView().addEventListener("consolidated", viewConsolidated, false);

function viewConsolidated(e) {
if (!isMainView) {
window.close();
}
}


C#:

ApplicationView.GetForCurrentView().Consolidated += ViewConsolidated;

void ViewConsolidated(ApplicationView sender, ApplicationViewConsolidatedEventArgs e)
{
if (!CoreApplication.GetCurrentView().IsMain)
{
Window.Current.Close();
}
}

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.

JavaScript:

Windows.UI.ViewManagement.ApplicationViewSwitcher.switchAsync(
replacementViewId,
viewIdToClose,
Windows.UI.ViewManagement.ApplicationViewSwitchingOptions.consolidateViews).done();

C#:

await ApplicationViewSwitcher.SwitchAsync(
replacementViewId,
viewIdToClose,
ApplicationViewSwitchingOptions.ConsolidateViews);

 

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:

See the Projection sample for more details.

Wrapping up

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:

- Chaitanya Sareen, Principal Program Manager Lead, Windows

1 Comments
You must be logged in to comment. Sign in or Join Now
  • Fantastic post!  In the Windows 8.1 Mail application, if I open an email in a new window and then close the main window, a 'back' arrow appears on the secondary window allowing the user to navigate to the main application view  - the secondary window effectively becomes the primary window.  Anyone know how this is being done, and/or how I might achieve similar functionality in my application?