UWP Series: App views: Intro

This is a Windows-developer-oriented blog post. Knowledge on universal Windows apps, Windows Runtime and C# are required to understand the topic. We always assume the context of a typical C#/XAML universal Windows app unless otherwise stated.

First sight into multiple-window apps

Two Calculator windows side by sideTwo Calculator windows side by sideTwo Calculator windows side by sideTwo Calculator windows side by side
Two Calculator windows side by side

As you and users may have noticed, some of the first-party apps, including Microsoft Edge, Calculator, Cortana (for Windows Phone 8.1) and IE Mobile 11 (for Windows Phone 8.1), can have multiple windows open at the same time. From time to time, you may have wondered how can a third-party developer provide such functionality for users.

An ordinary Windows app can have multiple windows open at the same time. Notepad is an example. However, notepad achieves such possibility with the ability to have multiple instances of notepad.exe running side by side. For Windows Store apps, this is not possible. A Windows Store app has its isolated storage (typically stored in C:\Users\<User Name>\AppData\Local\Packages\<Package Family Name>) and having multiple instances running can cause problems on accessing the storage, which is supposed to be available any time. Moreover, if multiple instances of a Windows Store app are running side by side, which process should Explorer talk to when user is tapping the tile of that app on Start? For many reasons, Windows Store apps are modelled as single instance apps. Therefore, you have to have multiple windows inside the same process to implement multiple-window functionality.

Understanding Windows Store app UI & threading model

Do not mess the UI from other threads. But you can tell the UI thread to mess itself.

— Nobody

A Windows Store app always have a 1:1 pairing of UI threads and views. You might have encountered the following buggy code:

DateTime pageConstructed;

public PageConstructor()
{
    DispatcherTimer dt = new DispatcherTimer();
    dt.Interval = new TimeSpan(0, 0, 1);
    dt.Tick += dt_Tick;
    pageConstructed = DateTime.Now;
    dt.Start();
}

private void dt_Tick()
{
    SomeViewModel.SecondsPast = (DateTime.Now - pageConstructed).TotalSeconds;
}

If you have ever bound the SecondsPast property, which implements INotifyPropertyChanged the usual way and is bound to some UI in OneWay or TwoWay mode, the code will throw an exception telling you that you cannot do this because the Tick event of that DispatcherTimer runs on a thread other than the UI thread.

Needless to say that any UI model that makes the tiniest sense blocks access to UI from any other thread. To fix the code, you reimplement the dt_Tick event handler like this:

private async void dt_Tick()
{
    await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
        () =>
        {
            SomeViewModel.SecondsPast = (DateTime.Now - pageConstructed).TotalSeconds;
        });
}

Use the dispatcher to schedule your delegate on the UI thread. This method is heavily used when dealing with multiple windows apps. So be sure to understand this trick.

A window is not a Window.

— Gee Law

A Calculator windowA Calculator windowA Calculator windowA Calculator window
A Calculator window

It is crucial to understand how Windows Store apps models windows, Windows and ApplicationViews to get things working. On desktop devices (with tablet mode turned off), a typical Windows Store app is contained in a standard window, with usual title bar (which you can customize with your own UI elements) and compulsory minimize, maximize and close buttons. This ensures Windows Store apps are tame since that is the whole point of Windows Store apps, that the installation, uninstallation and user experience are consistent and graceful. That means user can always minimize (which usually suspends the app), maximize or close a Windows Store app if he/she wants to. The app has no chance to make the user confirm if he really wants to close it (Microsoft Edge is special and can bypass such limitations). The correct way to prevent accidental data loss is to save the data when the app is suspending and recovers the data when appropriate.

window, app view and Windowwindow, app view and Windowwindow, app view and Windowwindow, app view and Window
window, app view and Window

When you see a window, like the Calculator window on the right, you actually see an app view. The graph on the left gives a simple understanding of the relations among a window, an app view and a Window.

What user calls a window, something with minimize, maximize (or restore down) and close button, is the outer-most guy. What is displayed inside a window is an app view. The app view also has an associated title bar style (whether the XAML extends into the title bar, the colours of system-defined elements and so on). A Window is, actually, a class in C# with WinRT. It always pairs with an app view and they are almost the same. We shall see this later.

The main view

When the app is activated for the first time, it has one UI thread and one app view, the main view. This view is very special and the speciality creates much trouble for us. We will tackle them in this series of blog posts. There is also a Window object associated with this view. The Window shall be called the main Window.

The UI thread associated with the main view is also the main thread of the app. All activation event handlers are called on this thread. No matter for whatever reason this thread terminates, the app crashes (unless the app is shutting down, of course).

Several jargons

An app view can consolidate. In Windows 8.1, an app view consolidates if it is no longer available from the recent apps list, or the user has ‘closed’ the view explicitly. By close, I mean performing the close gesture, pressing Alt+F4, clicking the close button on the title bar etc. In Windows 10, an app view consolidates if it is closed by user. For Windows 10 Mobile, I have not tried much on it and an app view surely consolidates if user taps the close button of that view on task switcher, or pulls it off the screen on task switcher. For Windows Phone 8.1, I have lost access to those devices so I cannot say a word about it. But that doesn’t really hurt since multiple-window is mainly for Windows 10 desktop family.

A Window can be closed by calling its Close method. Upon closing of a Window, the resources managed by the Window (including the UI elements) get released.

An app view is represented by an Windows.UI.ViewManagement.ApplicationView instance and a Window is really a Windows.UI.Xaml.Window object. There are also Windows.ApplicationModel.Core.CoreApplicationView and Windows.UI.Core.CoreWindow that are more low-level. However, you will see that you will inevitably use the four classes to achieve some functionalities.

Please enable JavaScript to view the comments powered by Disqus.