Chapter 3
App Anatomy and Page Navigation

During the early stages of writing this book, I was also working closely with a contractor to build a house for my family. While I wasn’t on site every day managing the whole effort, I was certainly involved in most decision-making throughout the home’s many phases, and I occasionally participated in the construction itself.

In the Sierra Nevada foothills of California, where I live, the frame of a house is built with the plentiful local wood, and all the plumbing and wiring has to be in the walls before installing insulation and wallboard (aka sheetrock). It amazed me how long it took to complete that infrastructure. The builders spent a lot of time adding little blocks of wood here and there to make it much easier for them to do the finish work later on (like hanging cabinets), and lots of time getting the wiring and plumbing put together properly. All of this became completely invisible to the eye once the wallboard went up and the finish work was in place.

But then, imagine what the house would be like without such careful attention to structural details. Imagine having some light switches that just didn’t work or controlled the wrong fixtures. Imagine if the plumbing leaked inside the walls. Imagine if cabinets and trim started falling off the walls after a week or two of moving into the house. Even if the house managed to pass final inspection, such flaws would make it almost unlivable, no matter how beautiful it might appear at first sight. It would be like a few of the designs of the famous architect Frank Lloyd Wright: very interesting architecturally and aesthetically pleasing, yet thoroughly uncomfortable to actually live in.

Apps are very much the same story—I’ve marveled, in fact, just how many similarities exist between the two endeavors! That is, an app might be visually beautiful, even stunning, but once you really start using it day to day, a lack of attention on the fundamentals will become painfully apparent. As a result, your customers will probably start looking for somewhere else to live, meaning someone else’s app!

This chapter, then, is about those fundamentals: the core foundational structure of an app upon which you can build something that can look beautiful and really work well. We’ll first complete our understanding of the hosted environment and then look at activation (how apps get running) and lifecycle transitions. We’ll then look at page navigation within an app, and we’ll see a few other important considerations along the way, such as working with multiple async operations.

Let me offer you advance warning that this is an admittedly longer and more intricate chapter than many that follow, since it specifically deals with the software equivalents of framing, plumbing, and wiring. With our house, I can completely attest that installing the lovely light fixtures my wife picked out seemed, in the moment, much more satisfying than the framing I’d done months earlier. But now, actually living in the house, I have a deep appreciation for all the nonglamorous work that went into it. It’s a place I want to be, a place in which my family and I are delighted, in fact, to spend the majority of our lives. And is that not how you want your customers to feel about your apps? Absolutely! Knowing the delight that a well-architected app can bring to your customers, let’s dive in and find our own delight in exploring the intricacies!

Local and Web Contexts within the App Host

As described in Chapter 1, “The Life Story of a Windows Store App,” apps written with HTML, CSS, and JavaScript are not directly executable like their compiled counterparts written in C#, Visual Basic, or C++. In our app packages, there are no EXEs, just .html, .css, and .js files (plus resources, of course) that are, plain and simple, nothing but text. So something has to turn all this text that defines an app into something that’s actually running in memory. That something is again the app host, wwahost.exe, which creates what we call the hosted environment for Store apps.

Let’s review what we’ve already learned in Chapter 1 and Chapter 2, “Quickstart,” about the characteristics of the hosted environment:

• The app host (and the apps in it) use brokered access to sensitive resources.

• Though the app host provides an environment very similar to that of Internet Explorer 10, there are a number of changes to the DOM API, documented on HTML and DOM API changes list and HTML, CSS, and JavaScript features and differences. A related topic is Windows Store apps using JavaScript versus traditional web apps.

• HTML content in the app package can be loaded into the local or web context, depending on the ms-appx:/// and ms-appx-web:/// scheme used to reference that content (the third / again means “in the app package”). Remote content (referred to with http[s]://) always runs in the web context.

• The local context has access to the WinRT API, among other things, whereas the web context is allowed to load and execute remote script but cannot access WinRT.

• ActiveX control plug-ins are generally not allowed in either context.

• The HTML5 postMessage function can be used to communicate between an iframe and its containing parent across contexts. This can be useful to execute remote script within the web context and pass the results to the local context; script acquired in the web context should not be itself passed to the local context and executed there. (Windows Store policy actually disallows this, and apps submitted to the Store will be analyzed for such practices.)

• Further specifics can be found on Features and restrictions by context, including which parts of WinJS don’t rely on WinRT and can thus be used in the web context. (WinJS, by the way, cannot be used on web pages outside of an app.)

Now what we’re really after in this chapter is not so much these characteristics themselves but their impact on the structure of an app. (To explore the characteristics themselves, refer to the Integrating content and controls from web services sample.) First and foremost is that an app’s home page, the one you point to in the manifest in the Start page field of the Application UI tab16, always runs in the local context, and any page to which you navigate directly (<a href> or document.location) must also be in the local context.

Next, a local context page can contain an iframe in either local or web context, provided that the src attribute refers to content in the app package (and by the way, programmatic read-only access to your package contents is obtained via Windows.ApplicationMode.Package.Current.InstalledLocation). Referring to any other location (http[s]:// or other protocols) will always place the iframe in the web context.

<!-- iframe in local context with source in the app package -->
<!-- this form is only allowed from inside the local context -->
<iframe src="/frame-local.html"></iframe>
<iframe src="ms-appx:///frame-local.html"></iframe>

<!-- iframe in web context with source in the app package -->
<iframe src="ms-appx-web:///frame-web.html"></iframe>

<!-- iframe with an external source automatically assigns web context -->
<iframe src="http://www.bing.com"></iframe>

Also, if you use an <a href="..." target="..."> tag with target pointing to an iframe, the scheme in href determines the context.

A web context page, for its part, can contain only a web context iframe; for example, the last two iframe elements above are allowed, whereas the first two are not. You can also use ms-appx-web:/// within the web context to refer to other content within the app package, such as images.

Although not commonly done within Windows Store apps for reasons we’ll see later in this chapter, similar rules apply with page-to-page navigation using <a href> or document.location. Since the whole scene here can begin to resemble overcooked spaghetti, the exact behavior for these variations and for iframes is described in the following table:

Image

When an iframe is in the web context, note that its page can contain ms-appx-web references to in-package resources, even if the page is loaded from a remote source (http[s]). Such pages, of course, would not work in a browser.

The last two items in the table really mean that a Windows Store app cannot navigate from its top-level page (in the local context) directly to a web context page of any kind (local or remote) and remain within the app: the browser will be launched instead. That’s just life in the app host! Such content must be placed in an iframe.

Similarly, navigating from a web context page to a local context page is not allowed by default, but you can enable this by calling the super-secret function MSApp.addPublicLocalApplicationUri from code in a local page (and it actually is well-documented) for each specific URI you need:

//This must be called from the local context
MSApp.addPublicLocalApplicationUri("ms-appx:///frame-local.html");

The Direct Navigation example for this chapter gives a demonstration of this (as does Scenario 6 of the Integrating content and controls from web services sample). Do be careful when the URI contains query parameters, however. For example, you don’t want to allow a website to navigate to something like ms-appx:///delete.html?file=superimportant.doc!

One other matter that arises here is the ability to grant a web context page access to specific functions like geolocation, writing to the clipboard, the app cache, and IndexedDB—things that web pages typically assume they can use. By default, the web context in a Store app has no access to such operating system capabilities. For example, create a new Blank project in Visual Studio with this one line of HTML in the body of default.html:

<iframe src="http://maps.bing.com" style="width:1366px; height: 768px"></iframe>

Then set the Location capability in the manifest (something I forgot on my first experiment with this!), and run the app. You’ll see the Bing page you expect.17 However, attempting to use geolocation from within that page—clicking the locator control to the left of “World,” for instance—will give you the kind of error shown in Figure 3-1.

Image

FIGURE 3-1 Use of brokered capabilities like geolocation from within a web context will generate an error.

Such capabilities are blocked because web content loaded into an iframe can easily provide the means to navigate to other arbitrary pages. From the Bing maps page above, for example, a user can go to the Bing home page, do a search, and end up on any number of untrusted and potentially malicious pages. Whatever the case, those pages might request access to sensitive resources, and if they just generated the same user consent prompts as an app, users could be tricked into granting such access.

Fortunately, if you ask nicely, Windows will let you enable those capabilities for web pages that the app knows about. All it takes is an affidavit signed by you and sixteen witnesses, and…OK, I’m only joking! You simply need to add what are called application content URI rules to your manifest. Each rule says that content from some URI is known and trusted by your app and can thus act on the app’s behalf. You can also exclude URIs, which is typically done to exclude specific pages that would otherwise be included within another rule.

Such rules are created in the Content Uri tab of Visual Studio’s manifest editor, as shown in Figure 3-2. Each rule needs to be the exact URI that might be making a request, such as http://www.bing.com/maps/. Once we add that rule (as in the completed ContentUri example for this chapter), Bing maps is allowed to use geolocation. When it does so, a message dialog will appear (Figure 3-3), just as if the app had made the request. (Note: When run inside the debugger, the ContentUri example might show a Permission Denied exception on startup. If so, press Continue within Visual Studio because this doesn’t affect the app running outside the debugger.)

Image

FIGURE 3-2 Adding a content URI to the app manifest; the contents of the text box is saved when the manifest is saved. Add New URI creates another set of controls in which to enter additional rules.

Image

FIGURE 3-3 With a content URI rule in place, web content in an iframe acts like part of the app, showing why content URI rules are necessary to protect the user from pages unknown to the app that could otherwise trick the user into granting access to sensitive resources.

As we’re talking about iframe elements here, there are a couple extra tips you might find helpful when using them. First, to prevent selection, style the iframe with –ms-user-select: none or set its style.msUserSelect property to "none" in JavaScript. Second, some web pages contain frame-breaking code that prevents the page from being loaded into an iframe, in which case the page will be opened in the default browser and not the app. If that page is essential to your app, you’ll need to work with the owner to create an alternate page that will work for you. Third, just as plug-ins aren’t supported in Windows Store apps, they’ll also fail to load for web pages loaded into an iframe. In short, pulling web content that you don’t own into an app is a risky business!

Furthermore, iframe support is not intended to let you just build an app out of remote web pages. Section 2.4 of the Windows 8 app certification requirements, in fact, specifically disallow apps that are just websites—the primary app experience must take place within the app, meaning that it doesn’t happen within websites hosted in iframe elements. A few key reasons for this are that websites typically aren’t set up well for touch interaction (which violates requirement 3.5) and often won’t work well in snapped view (violating requirement 3.6). In short, overuse of web content will likely mean that the app won’t be accepted by the Store.

Referencing Content from App Data: ms-appdata

As we’ve seen, the ms-appx[-web]:/// schema allow an app to navigate iframe elements to pages that exist inside the app package, or on the web. This begs a question: can an app point to content on the local file system that exists outside its package, such as a dynamically created file in an appdata folder? Can, perchance, an app use the file:// protocol to navigate and/or access that content?

Well, as much as I’d love to tell you that this just works, the answer is somewhat mixed. First, the file:// protocol is wholly blocked by design for various security reasons, even for your appdata folders to which you otherwise have full access. (Custom protocols are also unsupported in iframe src URIs.) Fortunately there is a substitute, ms-appdata:///, that fulfills part of the need. Within the local context of an app, ms-appdata:/// is a shortcut to the appdata folder wherein exist local, roaming, and temp folders. So, if you created a picture called image65.png in your appdata local folder, you can refer to it by using ms-appdata:///local/image65.png, and similar forms with roaming and temp, wherever a URI can be used, including within a CSS style like background.

Unfortunately, the caveat—there always seems to be one with the app container!—is that ms-appdata can be used only for resources, namely with the src attribute of img, video, and audio elements. It cannot be used to load HTML pages, CSS stylesheets, or JavaScript, nor can it be used for navigation purposes (iframe, hyperlinks, etc.). This is because it wasn’t feasible to create a sub-sandbox environment for such pages, without which it would be possible for a page loaded with ms-appdata:// to access everything in your app.

Can you do any kind of dynamic page generation, then? Well, yes: you need to load file contents and process them manually, inserting them into the DOM through innerHTML properties and such. You can get to your appdata folders through the Windows.Storage.ApplicationData API and go from there. To load and render a full HTML page requires that you patch up all external references and play some magic with script, but it can be done if you really want.

A similar question is whether you can generate and execute script on the fly. The answer is again qualified. Yes, you can take a JavaScript string and pass it to the eval or execScript functions. Be mindful, though, that the Windows Store certification requirements specifically disallow doing this with script obtained from a remote source in the local context (see section requirement 3.9). The other inevitable caveat here is that automatic filtering is applied to that code that prevents injection of script (and other risky markup) into the DOM via properties like innerHTML and outerHTML, and methods like document.write and DOMParser.parseFromString. Yet there are certainly situations where you, the developer, really know what you’re doing and enjoy juggling chainsaws and flaming swords and thus want to get around such restrictions, especially when using third-party libraries. (See the sidebar below.) Acknowledging that, Microsoft provides a mechanism to consciously circumvent all this: MSApp.execUnsafeLocalFunction. For all the details regarding this, refer to Developing secure apps, which covers this along with a few other obscure topics that I’m not including here. One such topic—the numerous variations of the sandbox attribute for iframes—is also demonstrated in the JavaScript iframe sandbox attribute sample.

And curiously enough, WinJS actually makes it easier for you to juggle chainsaws and flaming swords! WinJS.Utilities.setInnerHTMLUnsafe, setOuterHTMLUnsafe, and insertAdjacentHTMLUnsafe are wrappers for calling DOM methods that would otherwise strip out risky content.

All that said (don’t you love being aware of the details?), let’s look at an example of using ms-appdata, which will probably be much more common in your app-building efforts.

In general, Windows Store apps can employ libraries like jQuery, Prototype, Dojo, and so forth, as noted in Chapter 1. However, there are some limitations and caveats.

First, because local context pages in an app cannot load script from remote sources, apps typically need to include such libraries in their packages unless only being used from the web context. WinJS, mind you, doesn’t need bundling because it’s provided by the Windows Store, but such “framework packages” are not enabled for third parties in Windows 8.

Second, DOM API changes and app container restrictions might affect the library. For example, library functions using window.alert won’t work. One library also cannot load another library from a remote source in the local context. Crucially, anything in the library that assumes a higher level of trust than the app container provides (such as open file system access) will have issues.

The most common issue comes up when libraries inject elements or script into the DOM (as through innerHTML), a widespread practice for web applications that is not generally allowed within the app container. For example, trying to create a jQuery datepicker widget ($("myCalendar").datepicker()) will hurl out this kind of error. You can get around this on the app level by wrapping the code above with MSApp.execUnsafeLocalFunction, but that doesn’t solve injections coming from deeper inside the library. In the jQuery example given here, the control can be created but clicking a date in that control generates another error.

In short, you’re free to use third-party libraries so long as you’re aware that they were generally written with assumptions that don’t always apply within the app container. Over time, of course, fully Windows 8–compatible versions of such libraries will emerge.

Here My Am! with ms-appdata

OK! Having endured seven pages of esoterica, let’s play with some real code and return to the Here My Am! app we wrote in Chapter 2. Here My Am! used the convenient URL.createObjectURL method to display a picture taken through the camera capture UI in an img element:

captureUI.captureFileAsync(Windows.Media.Capture.CameraCaptureUIMode.photo)
    .done(function (capturedFile) {
        if (capturedFile) {
            that.src = URL.createObjectURL(capturedFile);
        }
    });

This is all well and good: we just take it on faith that the picture is stored somewhere so long as we get a URI. Truth is, pictures (and video) from the camera capture API are just stored in a temp file; if you set a breakpoint in the debugger and look at capturedFile, you’ll see that it has an ugly file path like C:\Users\kraigb\AppData\Local\Packages\ProgrammingWin8-JS-CH3-HereMyAm3a_5xchamk3agtd6\TempState\picture001.png. Egads. Not the friendliest of locations, and definitely not one that we’d want a typical consumer to ever see!

With an app like this, let’s copy that temp file to a more manageable location, to allow the user, for example, to select from previously captured pictures (as we’ll do in Chapter 8, “State, Settings, Files, and Documents”). We’ll make a copy in the app’s local appdata folder and use ms-appdata to set the img src to that location. Let’s start with the call to captureUI.captureFileAsync as before:

//For use across chained promises
var capturedFile = null;

captureUI.captureFileAsync(Windows.Media.Capture.CameraCaptureUIMode.photo)
    .then(function (capturedFileTemp) {
        //Be sure to check validity of the item returned; could be null if the user canceled.
        if (!capturedFileTemp) { throw ("no file captured"); }

Notice that instead of calling done to get the results of the promise, we’re using then instead. This is because we need to chain a number of async operations together and then allows errors to propagate through the chain, as we’ll see in the next section. In any case, once we get a result in capturedFileTemp (which is in a gnarly-looking folder), we then open or create a “HereMyAm” folder within our local appdata. This happens via Windows.Storage.ApplicationData.current.localFolder, which gives us a Windows.Storage.StorageFolder object that provides a createFolderAsync method:

       //As a demonstration of ms-appdata usage, copy the StorageFile to a folder called HereMyAm
       //in the appdata/local folder, and use ms-appdata to point to that.
       var local = Windows.Storage.ApplicationData.current.localFolder;
       capturedFile = capturedFileTemp;
       return local.createFolderAsync("HereMyAm",
           Windows.Storage.CreationCollisionOption.openIfExists);
   })
   .then(function (myFolder) {
       //Again, check validity of the result operations
       if (!myFolder) { throw ("could not create local appdata folder"); }

Assuming the folder is created successfully, myFolder will contain another StorageFolder object. We then use this as a target parameter for the temp file’s copyAsync method, which also takes a new filename as its second parameter. For that name we’ll just use the original name with the date/time appended (replacing colons with hypens to make a valid filename):

       //Append file creation time (should avoid collisions, but need to convert colons)
       var newName = capturedFile.displayName + " - "
           + capturedFile.dateCreated.toString().replace(/:/g, "-") + capturedFile.fileType;
       return capturedFile.copyAsync(myFolder, newName);
   })
   .done(function (newFile) {
       if (!newFile) { throw ("could not copy file"); }

Because this was the last async operating in the chain, we use the promise’s done method for reasons we’ll again see in a moment. In any case, if the copy succeeded, newFile contains a StorageFile object for the copy, and we can point to that using an ms-appdata URI:

       lastCapture = newFile; //Save for Share
       that.src = "ms-appdata:///local/HereMyAm/" + newFile.name;
   },
   function (error) {
       console.log(error.message);
   });

The completed code is in the HereMyAm3a example.

Of course, we could still use URL.createObjectURL with newFile as before (making sure to provide the { oneTimeOnly=true } parameter to avoid memory leaks). While that would defeat the purpose of this exercise, it works perfectly (and the memory overhead is essentially the same since the picture has to be loaded either way). In fact, we’d need to use it if we copy images to the user’s pictures library instead. To do this, just replace Windows.Storage.ApplicationData.current.localFolder with Windows.Storage.KnownFolders.picturesLibrary and declare the Pictures Library capability in the manifest. Both APIs give us a StorageFolder, so the rest of the code is the same except that we’d use URL.createObjectURL because we can neither use ms-appdata:// nor file:// to refer to the pictures library. The HereMyAm3a example contains this code in comments.

Sequential Async Operations: Chaining Promises

In the previous code example, you might have noticed how we throw exceptions whenever we don’t get a good result back from any given async operation. Furthermore, we have only a single error handler at the end, and there’s this odd construct of returning the result (a promise) from each subsequent async operation instead of just processing the promise then and there.

Though it may look odd at first, this is actually the most common pattern for dealing with sequential async operations because it works better than the more obvious approach of nesting. Nesting means to call the next async API within the completed handler of the previous one, fulfilling each with done. Here’s how the async calls in previous code would be placed with this approach (extraneous code removed for simplicity):

captureUI.captureFileAsync(Windows.Media.Capture.CameraCaptureUIMode.photo)
    .done(function (capturedFileTemp) {
        //...
        local.createFolderAsync("HereMyAm", ...)
            .done(function (myFolder) {
                //...
                capturedFile.copyAsync(myFolder, newName)
                    .done(function (newFile) {
                    })
            })
        });

The one advantage to this approach is that each completed handler will have access to all the variables declared before it. Yet the disadvantages begin to pile up. For one, there is usually enough intervening code between the async calls that the overall structure becomes visually messy. More significantly, error handling becomes significantly more difficult. When promises are nested, error handling must be done at each level; if you throw an exception at the innermost level, for instance, it won’t be picked up by any of the outer error handlers. Each promise thus needs its own error handler, making real spaghetti of the basic code structure:

   captureUI.captureFileAsync(Windows.Media.Capture.CameraCaptureUIMode.photo)
       .done(function (capturedFileTemp) {
           //...
           local.createFolderAsync("HereMyAm", ...)
               .done(function (myFolder) {
                   //...
                   capturedFile.copyAsync(myFolder, newName)
                       .done(function (newFile) {
                       },
                       function (error) {
                       })
               },
               function (error) {
               });
         },
     function (error) {
     });

I don’t know about you, but I really get lost in all the }’s and )’s (unless I try hard to remember my LISP class in college), and it’s hard to see which error function applies to which async call.

Chaining promises solves all of this with the small tradeoff of needing to declare a few extra temp variables outside the chain. With chaining, you return the next promise out of each completed handler rather than fulfilling it with done. This allows you to indent all the async calls only once, and it has the effect of propagating errors down the chain. When an error happens within a promise, you see, what comes back is still a promise object, and if you call its then method (but not done—see the next section), it will again return another promise object with an error. As a result, any error along the chain will quickly propagate through to the first available error handler, thereby allowing you to have only a single error handler at the end:

captureUI.captureFileAsync(Windows.Media.Capture.CameraCaptureUIMode.photo)
    .then(function (capturedFileTemp) {
        //...
        return local.createFolderAsync("HereMyAm", ...);
    })
    .then(function (myFolder) {
        //...
        return capturedFile.copyAsync(myFolder, newName);
    })
    .done(function (newFile) {
    },
    function (error) {
    })

To my eyes (and my aging brain), this is a much cleaner code structure—and it’s therefore easier to debug and maintain. If you like, you can even end the chain with a done(null, errorHandler) call, replacing the previous done with then:

captureUI.captureFileAsync(Windows.Media.Capture.CameraCaptureUIMode.photo)
    //...
    .then(function (newFile) {
    })
    .done(null, function (error) {
    })
})

Finally, a word about debugging chained promises (or nested ones, for that matter). Each step involves an async operation, so you can’t just step through as you would with synchronous code (otherwise you’ll end up deep inside WinJS). Instead, set a breakpoint on the first line within each completed handler and on the first line of the error function at the end. As each breakpoint is hit, you can step through that completed handler. When you reach the next async call, click the Continue button in Visual Studio so that the async operation can run, after which you’ll hit the breakpoint in the next completed handler (or the breakpoint in the error handler).

Error Handling Within Promises: then vs. done

Although it’s common to handle errors at the end of a chain of promises, as demonstrated in the code above, you can still provide an error handler at any point in the chain—then and done both take the same arguments. If an exception occurs at that level, it will surface in the innermost error handler.

This brings us to the difference between then and done. First, then returns another promise, thereby allowing chaining, whereas done returns undefined so it must be at the end of the chain. Second, if an exception occurs within one async operation’s then method and there’s no error handler at that level, the error gets stored in the promise returned by then. In contrast, if done sees an exception and there’s no error handler, it throws that exception to the app’s event loop. This will bypass any local (synchronous) try/catch block, though you can pick them up in either in WinJS.Application.onerror or window.onerror handlers. (The latter will get the error if the former doesn’t handle it.) If you don’t, the app will be terminated and an error report sent to the Windows Store dashboard. We actually recommend that you provide a WinJS.Application.onerror handler for this reason.

In practical terms, this means that if you end a chain of promises with a then and not done, all exceptions in that chain will get swallowed and you’ll never know there was a problem! This can place an app in an indeterminate state and cause much larger problems later on. So, unless you’re going to pass the last promise in a chain to another piece of code that will itself call done (as you would do if you’re writing a library from which you return promises), always use done at the end of a chain even for a single async operation.18

There is much more you can do with promises, by the way, like combining them, canceling them, and so forth. We’ll come back to all this at the end of this chapter.

Debug Output, Error Reports, and the Event Viewer

Speaking of exceptions and error handling, it’s sometimes heartbreaking to developers that window.prompt and window.alert are not available to Windows Store apps as quickie debugging aids. Fortunately, you have two other good options for that purpose. One is Windows.UI.Popups.Message-Dialog, which is actually what you use for real user prompts in general. The other is console.log, as shown earlier, which will send text to Visual Studio’s output pane. These messages can also be logged as Windows events, as we’ll see in a moment.19

Another DOM API function to which you might be accustomed is window.close. You can still use this as a development tool, but in released apps Windows interprets this call as a crash and generates an error report in response. This report will appear in the Store dashboard for your app, with a message telling you to not use it! After all, Store apps should not provide their own close affordances, as described in requirement 3.6 of the Store certification policy.

There might be situations, however, when a released app needs to close itself in response to unrecoverable conditions. Although you can use window.close for this, it’s better to use MSApp.-terminateApp because it allows you to also include information as to the exact nature of the error. These details show up in the Store dashboard, making it easier to diagnose the problem.

In addition to the Store dashboard, you should make fast friends with the Windows Event Viewer.20 This is where error reports, console logging, and unhandled exceptions (which again terminate the app without warning) can be recorded.

To enable this, you need to first navigate to Application and Services Log and expand Microsoft/Windows/AppHost, left-click to select Admin (this is important), right-click Admin, and then select View > Show Analytic and Debug Logs for full output, as shown in Figure 3-4. This will enable tracing for errors and exceptions. Then right-click AppTracing (also under AppHost) and select Enable Log. This will trace your calls to console.log as well as other diagnostic information coming from the app host.

Image

FIGURE 3-4 App host events, such as unhandled exceptions and load errors, can be found in Event Viewer.

We already introduced Visual Studio’s Exceptions dialog in Chapter 2; refer back to Figure 2-16. For each type of JavaScript exception, this dialog supplies two checkboxes labeled Thrown and User-unhandled. Checking Thrown will display a dialog box in the debugger (Figure 3-5) whenever an exception is thrown, regardless of whether it’s handled and before reaching any of your error handlers. If you have error handlers, you can safely click the Continue button in the dialog, and you’ll eventually see the exception surface in those error handlers. (Otherwise the app will terminate.) If you click Break instead, you can find the exception details in the debugger’s Locals pane, as shown in Figure 3-6.

Image

FIGURE 3-5 Visual Studio’s exception dialog. As the dialog indicates, it’s safe to press Continue if you have an error handler in the app; otherwise the app will terminate. Note that the checkbox in this dialog is a shortcut to toggle the Thrown checkbox for this exception type in the Exceptions dialog.

Image

FIGURE 3-6 Information in Visual Studio’s Locals pane when you Break on an exception.

The User-unhandled option (enabled for all exceptions by default) will display a similar dialog whenever an exception is thrown to the event loop, indicating that it wasn’t handled by an app-provided error function (“user” code from the system’s perspective).

You typically turn on Thrown only for those exceptions you care about; turning them all on can make it very difficult to step through your app! Still, you can try it as a test, and then leave checks only for those exceptions you expect to catch. Do leave User-unhandled checked for everything else; in fact, unless you have a specific reason not to, make sure that User-unhandled is checked next to JavaScript Runtime Exceptions here because this will include those exceptions not otherwise listed. This way you can catch (and fix) any exceptions that might abruptly terminate the app, which is something your customers should never experience.

App Activation

First, let me congratulate you for coming this far into a very detailed chapter! As a reward, let’s talk about something much more tangible and engaging: the actual activation of an app and its startup sequence. This can happen a variety of ways, such as via the Start screen tile, contracts, and file type and URI scheme associations. In all these activation cases, you’ll be writing plenty of code to initialize your data structures, reload previously saved state, and do everything to establish a great experience for your users.

Branding Your App 101: The Splash Screen and Other Visuals

With activation, we actually need to take a step back even before the app host gets loaded, back to the moment a user taps your tile on the Start screen or when your app is launched some other way. The very first thing that happens, before any app-specific code is loaded or run, is that Windows displays a splash screen composed of the image and background color you provide in your manifest.

The splash screen—which shows for at least 0.75 seconds so that it’s not just a flash—gives users something interesting to look at while the app gets started (much better than an hourglass). It also occupies the whole view where the app is being launched, so it’s a much more directly engaging experience for your users. This view can be the filled view state, the overlay area from the share or search charm, or the snapped view if the app is immediately snapped. During this time, an instance of the app host gets launched to load, parse, and render your HTML/CSS, and load, parse, and execute your JavaScript, firing events along the way as we’ll see in the next section. When the app’s first page is ready, the system removes the splash screen.

The splash screen, along with your app tile, is clearly one of the most important ways to uniquely brand your app, so make sure that you and your graphic artist(s) give full attention to these. There are additional graphics and settings in the manifest that also affect your branding and overall presence in the system, as shown in the table below. Be especially aware that the Visual Studio and Blend templates provide some default and thoroughly unattractive placeholder graphics. Thus, take a solemn vow right now that you truly, truly, cross-your-heart will not upload an app to the Windows Store with those defaults still in place! (For additional guidance, see Guidelines and checklist for splash screens.)

You can see that the table lists multiple sizes for various images specified in the manifest to accommodate varying pixel densities: 100%, 140%, and 180% scale factors, and even a few at 80% (don’t neglect the latter: they are typically used for most desktop monitors). So while you can just provide a single 100% scale image for each of these, it’s almost guaranteed that scaled-up versions of that graphic are going to look bad. So why not make your app look its best? Take the time to create each individual graphic consciously.

Image

In the table, note that 80% scale tile graphics are used in specific cases like low DPI modes (generally when the DPI is less than 130 and the resolution is less than 2560 x 1440) and should be provided with other scaled images. Note also that there are additional graphics besides the Packaging Logo (first item in the table) that you’ll need when uploading an app to the Windows Store. See the App images topic in the docs under “Promotional images” for full details.

When saving these files, append .scale-80, .scale-100, .scale-140, and .scale-180 to the filenames, before the file extension, as in splashscreen.scale-140.png. This allows you, both in the manifest and elsewhere in the app, to refer to an image with just the base name, such as splashscreen.png, and Windows will automatically load the appropriate variant for the current scale. Otherwise it looks for one without the suffix. No code needed! This is demonstrated in the HereMyAm3b example, where I’ve added all the various branded graphics (with some additional text in each graphic to show the scale). To test these different graphics, use the set resolution/scaling button in the simulator—refer to Figure 2-5 in Chapter 2—to choose different pixel densities on a 10.6” screen (1366 x 768 =100%, 1920 x 1080 = 140%, and 2560 x 1440 = 180%). You’ll also see the 80% scale used on the other display choices, including the 23” and 27” settings. In all cases, the setting affects which images are used on the Start screen and the splash screen, but note that you might need to exit and restart the simulator to see the new scaling take effect.

One thing you might also notice is that full-color photographic images don’t scale down very well to the smallest sizes (store logo and small logo). This is one reason why such logos are typically simpler with Windows Store app design, which also keeps them smaller when compressed. This is an excellent consideration to keep your package size smaller when you make more versions for different contrasts and languages. We’ll see more on this in Chapter 17, “Apps for Everyone.”

Tip Two other branding-related resources you might be interested in are the Branding your Windows Store app topic in the documentation (covering design aspects) and the CSS styling and branding your app sample (covering CSS variations and dynamically changing the active stylesheet).

Activation Event Sequence

As the app host is built on the same parsing and rendering engines as Internet Explorer, the general sequence of activation events is more or less what a web application sees in a browser. Actually, it’s more rather than less! When you launch an app from its tile, here’s the process as Windows sees it:

1. Windows displays a splash screen using information from the app manifest.

2. Windows launches the app host, identifying the app to launch.

3. The app host retrieves the app’s Start Page setting (see the Application UI tab in the manifest editor), which identifies the HTML page to load.

4. The app host loads that page along with referenced stylesheets and script (deferring script loading if indicated in the markup). Here it’s important that all files are properly encoded for best startup performance. (See the sidebar below.)

5. document.DOMContentLoaded fires. You can use this to do further initialization specifically related to the DOM, if desired (not common).

6. Windows.UI.WebUI.WebUIApplication.onactivated fires. This is typically where you’ll do all your startup work, instantiate WinJS and custom controls, initialize state, and so on.

7. The splash screen is hidden once the activated event handler returns (unless the app has requested a deferral as discussed later in the “Activation Deferrals” section).

8. body.onload fires. This is typically not used in Windows Store apps, though it might be utilized by imported code or third party libraries.

What’s also very different is that an app can again be activated for many different purposes, such as contracts and associations, even while it’s already running. As we’ll see in later chapters, the specific page that gets loaded (step 3) can vary by contract, and if a particular page is already running it will receive only the Windows.UI.WebUI.WebUIApplication.onactivated event and not the others.

For the time being, though, let’s concentrate on how we work with this core launch process, and because you’ll generally do your initialization work within the activated event, let’s examine that structure more closely.

To optimize bytecode generation when parsing HTML, CSS, and JavaScript, the Windows Store requires that all .html, .css, and .js files are saved with Unicode UTF-8 encoding. This is the default for all files created in Visual Studio or Blend. If you’re importing assets from other sources, check this encoding: in Visual Studio’s File Save As dialog (Blend doesn’t have this at present), select Save with Encoding and set that to Unicode (UTF-8 with signature) – Codepage 65001. The Windows App Certification Kit will issue warnings if it encounters files without this encoding.

Image

Image

Along these same lines, minification of JavaScript isn’t particularly important for Windows Store apps. Because an app package is downloaded from the Windows Store as a unit and often contains other assets that are much larger than your code files, minification won’t make much difference there. Once the package is installed, bytecode generation means that the package’s JavaScript has already been processed and optimized, so minification won’t have any additional performance impact.

Activation Code Paths

As we saw in Chapter 2, new projects created in Visual Studio or Blend give you the following code in js/default.js (a few comments have been removed):

(function () {
    "use strict";

    var app = WinJS.Application;
    var activation = Windows.ApplicationModel.Activation;

    app.onactivated = function (args) {
        if (args.detail.kind === activation.ActivationKind.launch) {
            if (args.detail.previousExecutionState !==
                activation.ApplicationExecutionState.terminated) {
                // TODO: This application has been newly launched. Initialize
                // your application here.
            } else {
                // TODO: This application has been reactivated from suspension.
                // Restore application state here.
            }
            args.setPromise(WinJS.UI.processAll());
        }
    };

    app.oncheckpoint = function (args) {
    };

    app.start();
})();

Let’s go through this piece by piece to review what we already learned and complete our understanding of this essential code structure:

(function () { … })(); surrounding everything is again the JavaScript module pattern.

"use strict" instructs the JavaScript interpreter to apply Strict Mode, a feature of ECMAScript 5. This checks for sloppy programming practices, like using implicitly declared variables, so it’s a good idea to leave it in place.

var app = WinJS.Application; and var activation = Windows.ApplicationMode.Activation; both create substantially shortened aliases for commonly used namespaces. This is a common practice to simplify multiple references to the same part of WinJS or WinRT.

app.onactivated = function (args) {…} assigns a handler for the WinJS.UI.onactivated event, which is a wrapper for Windows.UI.WebUI.WebUIApplication.onactivated. In this handler:

args.detail.kind identifies the type of activation.

args.detail.previousExecutionState identifies the state of the app prior to this activation, which determines whether to reload session state.

WinJS.UI.processAll instantiates WinJS controls—that is, elements that contain a data-win-control attribute, as we’ll cover in Chapter 4, “Controls, Control Styling, and Data Binding.”

args.setPromise instructs Windows to wait until WinJS.UI.processAll is complete before removing the splash screen. (See “Activation Deferrals” later in this chapter.)

app.oncheckpoint gets an empty handler in the template; we’ll cover this in the “App Lifecycle Transition Events” section later in this chapter.

app.start() (WinJS.Application.start()) initiates processing of events that WinJS queues during startup.

Notice how we’re not directly handling any of the events that Windows is firing, like DOMContent-Loaded or Windows.UI.WebUI.WebUIApplication.onactivated. Are we just ignoring those events? Not at all: one of the convenient services that WinJS offers through WinJS.UI.Application is a simplified structure for activation and other app lifetime events. Entirely optional, but very helpful.

With start, for example, a couple of things are happening. First, the WinJS.Application object listens for a variety of events that come from different sources (the DOM, WinRT, etc.) and coalesces them into a single object with which you register your own handlers. Second, when WinJS.Application receives activation events, it doesn’t just pass them on to the app’s handlers, because your handlers might not, in fact, have been set up yet. So it queues those events until the app says it’s really ready by calling start. At that point WinJS goes through the queue and fires those events. That’s really all there is to it.

As the template code shows, apps typically do most of their initialization work within the activated event, where there are a number of potential code paths depending on the values in args.details (an IActivatedEventArgs object). If you look at the documentation for WinJS.Application.onactivated, you’ll see that the exact contents of args.details depends on specific activation kind. All activations, however, share three common properties:

Image

Additional properties provide relevant data for the activation. For example, launch provides the tileId and arguments from secondary tiles. (See Chapter 13, “Tiles, Notifications, the Lock Screen, and Background Tasks”). The search kind (the next most commonly used) provides queryText and language, protocol provides a uri, and so on. We’ll see how to use many of these in their proper contexts, and sometimes they apply to altogether different pages than default.html. What’s contained in the templates (and what we’ve already used for an app like Here My Am!) is primarily to handle normal startup from the app tile (or within Visual Studio’s debugger).

WinJS.Application Events

WinJS.Application isn’t concerned only with activation—its purpose is to centralize events from several different sources and turn them into events of its own. Again, this enables the app to listen to events from a single source (either assigning handlers via addEventListener(<event>) or on<event> properties; both are supported). Here’s the full rundown on those events and when they’re fired (if queued, the event is fired within WinJS.Application.start):

activated Queued in the local context for Windows.UI.WebUI.WebUIApplication.-onactivated. In the web context, where WinRT is not applicable, this is instead queued for DOMContentLoaded (where the launch kind will be launch and previousExecutionState is set to notRunning).

loaded Queued for DOMContentLoaded in all contexts;21 in the web context, will be queued prior to activated.

ready Queued after loaded and activated. This is the last one in the activation sequence.

error Fired if there’s an exception in dispatching another event. (If the error is not handled here, it’s passed onto window.onerror.)

checkpoint This tells the app when to save the session state it needs to restart from a previous state of terminated. It’s fired in response to both the document’s beforeunload event, as well as Windows.UI.WebUI.WebUIApplication.onsuspending.

unload Also fired for beforeunload after the checkpoint event is fired.

settings Fired in response to Windows.UI.ApplicationSettings.SettingsPane.-oncommandsrequested. (See Chapter 8.)

With most of these events (except error and settings), the args you receive contains a method called setPromise. If you need to perform an async operation (like an XmlHttpRequest) within an event handler, you can obtain the promise for that work and hand it off to setPromise instead of calling its then or done yourself. WinJS will then not process the next event in the queue until that promise is fulfilled. Now to be honest, there’s no actual difference between this and just calling done on the promise yourself within the loaded, ready, and unload events. It does make a difference with activated and checkpoint (specifically the suspending case) because Windows will otherwise assume that you’ve done everything you need as soon as you return from the handler; more on this in the “Activation Deferrals” section. So, in general, if you have async work within these events handlers, it’s a good habit to use setPromise. Because WinJS.UI.processAll is itself an async operation, the templates wrap it with setPromise so that the splash screen isn’t removed until WinJS controls have been fully instantiated.

I think you’ll generally find WinJS.Application to be a useful tool in your apps, and it also provides a few more features as documented on the WinJS.Application page. For example, it provides local, temp, roaming, and sessionState properties, which are helpful for managing state as we’ll see later on in this chapter and in Chapter 8.

The other bits are the queueEvent and stop methods. The queueEvent method drops an event into the queue that will get dispatched, after any existing queue is clear, to whatever listeners you’ve set up on the WinJS.Application object. Events are simply identified with a string, so you can queue an event with any name you like, and call WinJS.Application.addEventListener with that same name anywhere else in the app. This can be useful for centralizing custom events that you might invoke both during startup and at other points during execution without creating a separate global function for that purpose. It’s also a powerful means through which separately defined, independent components can raise events that get aggregated into a single handler. (For an example of using queueEvent, see Scenario 2 of the App model sample.)

As for stop, this is provided to help with unit testing so that you can simulate different activation sequences without having to relaunch the app and somehow simulate the right conditions when it restarts. When you call stop, WinJS removes its listeners, clears any existing event queue, and clears the sessionState object, but the app continues to run. You can then call queueEvent to populate the queue with whatever events you like and then call start again to process that queue. This process can be repeated as many times as needed.

Extended Splash Screens

Now, though the default splash screen helps keep the user engaged, they won’t stay engaged if that same splash screen stays up for a really long time. In fact, “a really long time” for the typical consumer amounts to all of 15 seconds, at which point they’ll pretty much start to assume that the app has hung and return to the Start screen to launch some other app that won’t waste their afternoon.

In truth, so long as the user keeps your app in the foreground and doesn’t switch away, Windows will give you all the time you need. But if the user switches to the Start screen or another app, you’re subject to a 15-second timeout. If you’re not in the foreground, Windows will wait only 15 seconds for an app to get through app.start and the activated event, at which point your home page should be rendered. Otherwise, boom! Windows automatically terminates your app.

The first consideration, of course, is to optimize your startup process to be as quick as possible. Still, sometimes an app really needs more than 15 seconds to get going, especially the first time it’s run after being installed, so it should let the user know that something is happening. For example, an app package might include a bunch of compressed data when downloaded from the Store, which it needs to expand onto the local file system on first run so that subsequent launches are much faster. Many games do this with graphics and other resources, optimizing the local storage for device characteristics; other apps might populate a local IndexedDB from data in a JSON file or download and cache a bunch of data from an online service.

It’s also possible that the user is trying to launch your app shortly after rebooting the system, in which case there might be lots of disk activity going on. If you load data from disk in your activation path, your process could take much longer than usual.

In all these cases, whenever an app is at risk of exceeding 15 seconds, you want to implement an extended splash screen. This means hiding your real home page behind another div that looks exactly like the system-provided splash screen but that is under the app’s control so that it can display progress indicators or other custom UI while initialization continues.

In general, Microsoft recommends that the extended splash screen initially matches the system splash screen to avoid visual jumps. (See Guidelines and checklist for splash screens.) At this point many apps simply add a progress indicator with some kind of a “Please go grab a drink, do some jumping jacks, or enjoy a few minutes of meditation while we load everything” message. Matching the system splash screen, however, doesn’t mean that the extended splash screen has to stay that way. A number of apps start with a replica of the system splash screen and then animate the graphic to one side to make room for other elements. Other apps fade out the initial graphic and start a video.

Making a smooth transition is the purpose of the args.detail.splashScreen object included with the activated event. This object—see Windows.ApplicationModel.Activation.-SplashScreen—contains an imageLocation property (a Windows.Foundation.Rect) containing the placement and size of the splash screen image. Because your app can be run on a variety of different display sizes, this tells you where to place the same image on your own page, where to start an animation, and/or where to place things like messages and progress indicators relative to that image.

The splashScreen object also provides an ondismissed event so that you can perform specific actions when the system-provided splash screen is dismissed and your first page comes up. Typically, this is useful to trigger the start of on-page animations, starting video playback, and so on.

For an example of an extended splash screen, refer to the Splash screen sample. One more detail that’s worth mentioning is that because an extended splash screen is just a page in your app, it can be placed into the various view states such as snapped view. So, as with every other page in your app, make sure your extended splash screen handles those states!

Activation Deferrals

As mentioned earlier, once you return from the activated event, Windows assumes that you’ve done everything you need on startup. By default, then, Windows will remove its splash screen and make your home page visible. But what if you need to complete one or more async operations before that home page is really ready, such as completing WinJS.UI.processAll?

This, again, is what the args.setPromise method inside the activated event is for. If you give your async operation’s promise to setPromise, Windows will wait until that promise is fulfilled before taking down the splash screen. The templates again use this to keep the system splash screen up until WinJS.UI.processAll is complete.

As setPromise just waits for a single promise to complete, how do you handle multiple async operations? You can do this a couple of ways. First, if you need to control the sequencing of those operations, you can chain them together as we already know how to do—just be sure that the end of the chain is a promise that becomes the argument to setPromise—don’t call its done method (use then if needed)! If the sequence isn’t important but you need all of them to complete, you can combine those promises by using WinJS.Promise.join, passing the result to setPromise. If you need only one of the operations to complete, you can use WinJS.Promise.any instead—join and any are discussed in the last section of this chapter.

The other means is to register more than one handler with WinJS.Application.onactivated; each handler will get its own event args and its own setPromise function, and WinJS will combine those returned promises together with WinJS.Promise.join.

Now the setPromise method coming from WinJS is actually implemented using a more generic deferral mechanism from WinRT. The args given to Windows.UI.WebUI.WebUIApplication.-onactivated (the WinRT event) contains a little method called getDeferral (technically Windows.-UI.WebUI.ActivatedOperation.getDeferral). This function returns a deferral object that contains a complete method, and Windows will leave the system splash screen up until you call that method (although this doesn’t change the fact that users are impatient and your app is still subject to the 15-second limit!). The code looks like this:

//In the activated handler
var activatedDeferral = Windows.UI.WebUI.ActivatedOperation.getDeferral();

someOperationAsync().done(function () {
    //After initialization is complete
    activatedDeferral.complete();
}

Of course, setPromise ultimately does exactly this, and if you add a handler for the WinRT activated event directly, you can use the deferral yourself.

App Lifecycle Transition Events and Session State

To an app—and the app’s publisher—a perfect world might be one in which consumers ran that app and stayed in that app forever (making many in-app purchases, no doubt!). Well, the hard reality is that this just isn’t reality. No matter how much you’d love it to be otherwise, yours is not the only app that the user will ever run. After all, what would be the point of features like sharing or snapping if you couldn’t have multiple apps running together? For better or for worse, users will be switching between apps, changing view states, and possibly closing your app. But what you can do is give energy to the “better” side of the equation by making sure your app behaves well under all these circumstances.

The first consideration is focus, which applies to controls in your app as well as to the app itself. Here you can simply use the standard HTML blur and focus events. For example, an action game or one with a timer would typically pause itself on blur and perhaps restart again on focus.

A similar but different condition is visibility. An app can be visible but not have the focus, as when it’s snapped. In such cases an app would continue things like animations or updating a feed, but it would stop such activities when visibility is lost (that is, when the app is actually in the background). For this, use the visibilitychange event in the DOM API, and then examine the visibilityState property of the window or document object, as well as the document.hidden property. (The event works for visibility of individual elements as well.) A change in visibility is also a good time to save user data like documents or game progress.

For view state changes, an app can detect these in several ways. As shown in the Here My Am! example, an app typically uses media queries (in declarative CSS or in code through media query listeners) to reconfigure layout and visibility of elements, which is really all that view states should affect. (Again, view state changes never change the mode of the app, just layout and object visibility.) At any time, an app can also retrieve the current view state through Windows.UI.ViewManagement.-ApplicationView.value. This returns one of the Windows.UI.ViewManagement.ApplicationViewState values: snapped, filled, fullScreenLandscape, and fullScreenPortrait; details in Chapter 6, “Layout.”

When your app is closed (the user swipes top to bottom or presses Alt+F4), it’s important to note that the app is first moved off-screen (hidden), suspended, and then closed, so the typical DOM events like unload aren’t much use. A user might also kill your app in Task Manager, but this won’t generate any events in your code either. Remember also that apps should not close themselves, as discussed before, but they can use MSApp.terminateApp to close due to unrecoverable conditions.

Suspend, Resume, and Terminate

Beyond focus, visibility, and view states, there are three other critical moments in an app’s lifetime:

Suspending When an app is not visible in any view state, it will be suspended after five seconds (according to the wall clock) to conserve battery power. This means it remains wholly in memory but won’t be scheduled for CPU time and thus won’t have network or disk activity (except when using specifically allowed background tasks). When this happens, the app receives the Windows.UI.WebUI.WebUIApplication.onsuspending event, which is also exposed through WinJS.Application.oncheckpoint. Apps must return from this event within the five-second period, or Windows will assume the app is hung and terminate it (period!). During this time, apps save transient session state and should also release any exclusive resources acquired as well, like file streams or device access. (See How to suspend an app.)

Resuming If the user switches back to a suspended app, it receives the Windows.UI.WebUI.-WebUIApplication.onresuming event. (This is not surfaced through WinJS.Application because it’s not commonly used and WinJS has no value to add.) We’ll talk more about this in the “Data from Services and WinJS.xhr” section coming up soon, because the need for this event often arises when using services. In addition, if you’re tracking sensor input of any kind (like compass, geolocation, or orientation), resuming is a good time to get a fresh reading. You’ll also want to check license status for your app and in-app purchases if you’re using trials and/or expirations (see Chapter 17). There are also times when you might want to refresh your layout (as we’ll see in Chapter 6), because it’s possible for your app to resume directly into a different view state than when it was suspended or to a different screen resolution as when the device has been connected to an external monitor. The same goes for enabling/disabling clipboard commands.

Terminating When suspended, an app might be terminated if there’s a need for more memory. There is no event for this, because by definition the app is already suspended and no code can run. Nevertheless, this is important for the app lifecycle because it affects previousExecutionState when the app restarts.

It’s very helpful to know that you can simulate these conditions in the Visual Studio debugger by using the toolbar drop-down shown in Figure 3-7. These commands will trigger the necessary events as well as set up the previousExecutionState value for the next launch of the app. (Be very grateful for these controls—there was a time when we didn’t have them, and it was painful to debug these conditions!)

Image

FIGURE 3-7 The Visual Studio toolbar drop-down to simulate suspend, resume, and terminate.

We’ve briefly listed those previous states before, but let’s see how they relate to the events that get fired and the previousExecutionState value that shows up when the app is next launched. This can get a little tricky, so the transitions are illustrated in Figure 3-8 and the table below describes how the previousExecutionState values are determined.

Image

Image

FIGURE 3-8 Process lifecycle events and previousExecutionState values.

The big question for the app, of course, is not so much what determines the value of previous-ExecutionState as what it should actually do with this value during activation. Fortunately, that story is a bit simpler and one that we’ve already seen in the template code:

• If the activation kind is launch and the previous state is notrunning or closedByUser, the app should start up with its default UI and apply any persistent state or settings. With closedByUser, there might be scenarios where the app should perform additional actions (such as updating cached data) after the user explicitly closed the app and left it closed for a while.

• If the activation kind is launch and the previous state is terminated, the app should start up in the same state as when it was last suspended.

• For launch and other activation kinds that include additional arguments or parameters (as with secondary tiles, toast notifications, and contracts), it should initialize itself to serve that purpose by using the additional parameters. The app might already be running, so it won’t necessarily initialize its default state again.

The second requirement above is exactly why the templates provide a code structure for this case along with a checkpoint handler. We’ll see the full details of saving and reloading state in Chapter 8. The basic idea is that an app should, when being suspended if not sooner, save whatever transient session state it would need to rehydrate itself after being terminated. This includes unsubmitted form data, scroll positions, the navigation stack, and other variables. This is because although Windows might have suspended the app and dumped it from memory, it’s still running in the user’s mind. Thus, when users activate the app again for normal use (activation kind is launch, rather than through a contract), they expect that app to be right where it was before. By the time an app gets suspended, then, it needs to have saved whatever state is necessary to make this possible. It then restores that state when previousExecutionState is terminated.

For more on app design where this is concerned, see Guidelines for app suspend and resume. Be clear that if the user directly closes the app with Alt+F4 or the swipe-down gesture, the suspending and checkpoint events will also be raised, so the app still saves session state. However, the app will be automatically terminated after being suspended, and it won’t be asked to reload session state when it’s restarted because previousExecutionState will be notRunning or closedByUser.

It works out best, actually, to save session state as it changes during the app’s lifetime, thereby minimizing the work needed within the suspending event (where you have only five seconds). Mind you, this session state does not include data that is persistent across sessions like user files, high scores, and app settings, because an app would always reload or reapply such persistent data in each activation path. The only concern here is maintaining the illusion that the app was always running.

You always save session state to your appdata folders or settings containers, which are provided by the Windows.Storage.ApplicationData API. Again, we’ll see all the details in Chapter 8. What I want to point out here are a few helpers that WinJS provides for all this.

First is the WinJS.Application.checkpoint event, which provides a single convenient place to save both session state and any other persistent data you might have, if you haven’t already done so.

Second is the WinJS.Application.sessionState object. On normal startup, this is just an empty object to which you can add whatever properties you like, including other objects. A typical strategy is to just use sessionState directly as a container for variables. Within the checkpoint event, WinJS automatically serializes the contents of this object (using JSON.stringify) into a file within your local appdata folder (meaning that variables in sessionState must have a string representation). Note that because the WinJS ensures that its own handler for checkpoint is always called after your app gets the event, you can be assured that WinJS will save whatever you write into sessionState at any time before your checkpoint handler returns.

Then, when the app is activated with the previous state of terminated, WinJS automatically rehydrates the sessionState object so that everything you put there is once again available. If you’ve used this object for storing variables, you only need to avoid settings those values back to their defaults when reloading your state.

Third, if you don’t want to use the sessionState object or have state that won’t work with it, the WinJS.Application object makes it easy to write your own files without having to use async WinRT APIs. Specifically, it provides (as shown in the documentation) local, temp, and roaming objects that each have methods called readText, writeText, exists, and remove. These objects each work within their respective appdata folders and provide a simplified API for file I/O, as shown in Scenario 1 of the App model sample.

A final aid ties into a deferral mechanism like the one for activation. The deferral is important because Windows will suspend your app as soon as you return from the suspending event. If you need a deferral for async operations, the event args for WinJS.Application.oncheckpoint provides a setPromise method that ties into the underlying WinRT deferral. As before, you pass a promise for an async operation (or combined operations) to setPromise, which in turn calls the deferral’s complete method once the promise is fulfilled.

On the WinRT level, the event args for suspending contains an instance of Windows.UI.WebUI.-WebUIApplication.SuspendingOperation. This provides a getDeferral method that returns a deferral object with a complete method as with activation.

Well, hey! That sounds pretty good—is this perhaps a sneaky way to circumvent the restriction on running Windows Store apps in the background? Will my app keep running indefinitely if I request a deferral by never calling complete?

No such luck, amigo. Accept my apologies for giving you a fleeting moment of exhilaration! Deferral or not, five seconds is the most you’ll ever get. Still, you might want to take full advantage of that time, perhaps to first perform critical async operations (like flushing a cache) and then to attempt other noncritical operations (like a sync to a server) that might greatly improve the user experience. For such purposes, the suspendingOperation object also contains a deadline property, a Date value indicating the time in the future when Windows will forcibly suspend you regardless of any deferral. Once the first operation is complete, you can check if you have time to start another, and so on.

A basic demonstration of using the suspending deferral, by the way, can be found in the App activated, resume, and suspend sample. This also provides an example of activation through a custom URI scheme, a subject that we’ll be covering later in Chapter 12, “Contracts.” An example of handling state, in addition to the updates we’ll make to Here My Am! in the next section, can be found in Scenario 3 of the App model sample.

Basic Session State in Here My Am!

To demonstrate some basic handling of session state, I’ve made a few changes to Here My Am! as given in the HereMyAm3c example. Here we have two pieces of information we care about: the variables lastCapture (a StorageFile with the image) and lastPosition (a set of coordinates). We want to make sure we save these when we get suspended so that we can properly apply those values when the app gets launched with the previous state of terminated.

With lastPosition, we can just move this into the sessionState object (prepending app.-sessionState.) as in the completed handler for getGeopositionAsync:

gl.getGeopositionAsync().done(function (position) {
    app.sessionState.lastPosition = {
        latitude: position.coordinate.latitude,
        longitude: position.coordinate.longitude
    };

    updatePosition();
    }, function (error) {
        console.log("Unable to get location.");
    });
}

Because we’ll need to set the map location from here and from previously saved coordinates, I’ve moved that bit of code into a separate function that also makes sure a location exists in sessionState:

function updatePosition() {
    if (!app.sessionState.lastPosition) {
        return;
    }

    callFrameScript(document.frames["map"], "pinLocation",
        [app.sessionState.lastPosition.latitude, app.sessionState.lastPosition.longitude]);
}

Note also that app.sessionState is initialized to an empty object by default, { }, so lastPosition will be undefined until the geolocation call succeeds. This also works to our advantage when rehydrating the app. Here’s what the previousExecutionState conditions look like for this:

if (args.detail.previousExecutionState !==
    activation.ApplicationExecutionState.terminated) {
    //Normal startup: initialize lastPosition through geolocation API
} else {
    //WinJS reloads the sessionState object here. So try to pin the map with the saved location
    updatePosition();
}

Because we stored lastPosition in sessionState, it will have been automatically saved in WinJS.Application.checkpoint when the app ran previously. When we restart from terminated, WinJS automatically reloads sessionState; if we’d saved a value there previously, it’ll be there again and updatePosition just works.

You can test this by running the app with these changes and then using the Suspend and shutdown option on the Visual Studio toolbar. Set a breakpoint on the updatePosition call above, and then restart the app in the debugger. You’ll see that sessionState.lastPosition is initialized at that point.

With the last captured picture, we don’t need to save the StorageFile, just the pathname: we copied the file into our local appdata (so it persists across sessions already) and can just use the ms-appdata:// URI scheme to refer to it. When we capture an image, we just save that URI into sessionState.imageURL (the property name is arbitrary) at the end of the promise chain inside capturePhoto:

app.sessionState.imageURL = "ms-appdata:///local/HereMyAm/" + newFile.name;
that.src = app.sessionState.imageURL

This value will also be reloaded when necessary during startup, so we can just initialize the img src accordingly:

if (app.sessionState.imageURL) {
    document.getElementById("photo").src = app.sessionState.imageURL;
}

This will initialize the image display from sessionState, but we also need to initialize lastCapture so that the same image is available through the Share contract. For this we need to also save the full file path so we can re-obtain the StorageFile through Windows.Storage.StorageFile.getFileFromPathAsync (which doesn’t work with ms-appdata:// URIs). So, in capturePhoto:

app.sessionState.imagePath = newFile.path;

And during startup:

if (app.sessionState.imagePath) {
    Windows.Storage.StorageFile.getFileFromPathAsync(app.sessionState.imagePath)
        .done(function (file) {
            lastCapture = file;

            if (app.sessionState.imageURL) {
                document.getElementById("photo").src = app.sessionState.imageURL;
            }
        });

I’ve placed the code to set the img src inside the completed handler here because we want the image to appear only if we can also access its StorageFile again for sharing. Otherwise the two features of the app would be out of sync.

In all of this, note again that we don’t need to explicitly reload these variables within the terminated case because WinJS reloads sessionState automatically. If we managed our state more directly, such as storing some variables in roaming settings within the checkpoint event, we would reload and apply those values at this time.

Note Using ms-appdata:/// and getFileFromPathAsync works because the file exists in a location that we can access programmatically by default. It also works for libraries for which we declare a capability in the manifest. If, however, we obtained a StorageFile from the file picker, we’d need to save that in the Windows.Storage.AccessCache to preserve access permissions across sessions.

Data from Services and WinJS.xhr

Though we’ve seen examples of using data from an app’s package (via URIs or Windows.ApplicationModel.Package.current.installedLocation) as well as in appdata, it’s very likely that your app will incorporate data from a web service and possibly send data to services as well. For this, the most common method is to employ XmlHttpRequest. You can use this in its raw (async) form, if you like, or you can save yourself a whole lot of trouble by using the WinJS.xhr function, which conveniently wraps the whole business inside a promise.

Making the call is quite easy, as demonstrated in the SimpleXhr example for this chapter. Here we use WinJS.xhr to retrieve the RSS feed from the Windows 8 developer blog:

WinJS.xhr({ url: "http://blogs.msdn.com/b/windowsappdev/rss.aspx" })
    .done(processPosts, processError, showProgress);

That is, give WinJS.xhr a URI and it gives back a promise that delivers its results to your completed handler (in this case processPosts) and will even call a progress handler if provided. With the former, the result contains a responseXML property, which is a DomParser object. With the latter, the event object contains the current XML in its response property, which we can easily use to display a download count:

function showProgress(e) {
    var bytes = Math.floor(e.response.length / 1024);
    document.getElementById("status").innerText = "Downloaded " + bytes + " KB";
}

The rest of the app just chews on the response text looking for item elements and displaying the title, pubDate, and link fields. With a little styling (see default.css), and utilizing the WinJS typography style classes of win-type-x-large (for title), win-type-medium (for pubDate), and win-type-small (for link), we get a quick app that looks like Figure 3-9. You can look at the code to see the details.22

Image

FIGURE 3-9 The output of the SimpleXhr app.

For a fuller demonstration of XHR and related matters, refer to the XHR, handling navigation errors, and URL schemes sample along with the tutorial called How to create a mashup in the docs. I don’t go into much detail with XHR in this book because it’s primarily a matter of retrieving and processing data that has little to do with the Windows 8 platform. Instead, what concerns us here are the implications of suspend and resume.

In particular, an app cannot predict how long it will stay suspended before being resumed or before being terminated and restarted.

In the first case, an app that gets resumed will have all its previous data still in memory. It very much needs to decide, then, whether that data has become stale since the app was suspended and whether sessions with other servers have exceeded their timeout periods. You can also think of it this way: after what period of time will users not remember nor care what was happening the last time they saw your app? If it’s a week or longer, it might be reasonable to resume or restart in a default state. Then again, if you pick up right back where they were, users gain increasing confidence that they can leave apps running for a long time and not lose anything. Or you can compromise and give the user options to choose from. You’ll have to think through your scenario, of course, but if there’s any doubt, resume where the app left off.

To check elapsed time, save a timestamp on suspend (from new Date().getTime()), get another timestamp in the resuming event, take the difference, and compare that against your desired refresh period. A Stock app, for example, might have a very short period. With the Windows 8 developer blog, on the other hand, new posts don’t show up more than once a day, so a much longer period on the order of hours is sufficient to keep up-to-date and to catch new posts within a reasonable timeframe.

This is implemented in SimpleXhr by first placing the WinJS.xhr call into a separate function called downloadPosts, which is called on startup. Then we register for the resuming event with WinRT:

Windows.UI.WebUI.WebUIApplication.onresuming = function () {
    app.queueEvent({ type: "resuming" });
}

Remember how I said we could use WinJS.Application.queueEvent to raise our own events to the app object? Here’s a great example. WinJS.Application doesn’t automatically wrap the resuming event because it has nothing to add to that process. But the code below accomplishes exactly the same thing, allowing us to register an event listener right alongside other events like checkpoint:

app.oncheckpoint = function (args) {
    //Save in sessionState in case we want to use it with caching
    app.sessionState.suspendTime = new Date().getTime();
};

app.addEventListener("resuming", function (args) {
    //This is a typical shortcut to either get a variable value or a default
    var suspendTime = app.sessionState.suspendTime || 0;

    //Determine how much time has elapsed in seconds
    var elapsed = ((new Date().getTime()) - suspendTime) / 1000;

    //Refresh the feed if > 1 hour (or use a small number for testing)
    if (elapsed > 3600) {
        downloadPosts();
    }
});

To test this code, run it in Visual Studio’s debugger and set breakpoints within these events. Then click the suspend button in the toolbar (refer back to Figure 3-7), and you should enter the checkpoint handler. Wait a few seconds and click the resume button (play icon), and you should be in the resuming handler. You can then step through the code and see that the elapsed variable will have the number of seconds that have passed, and if you modify that value (or change 3600 to a smaller number), you can see it call downloadPosts again to perform a refresh.

What about launching from the previously terminated state? Well, if you didn’t cache any data from before, you’ll need to refresh it again anyway. If you do cache some of it, your saved state (such as the timestamp) helps you decide whether to use the cache or load data anew.

It’s worth mentioning here that you can use HTML5 mechanisms like localStorage, IndexedDB, and the app cache for caching purposes; data for these is stored within your local appdata folder. And speaking of databases, you may be wondering what’s available for Windows Store apps other than IndexedDB. One option is SQLite, as described in Using SQLite in a Windows Store app (on the blog of Tim Heuer, one of the Windows 8 engineers). You can also use the OData Library for JavaScript that’s available from http://www.odata.org/libraries. It’s one of the easiest ways to communicate with an online SQL Server database (or any other with an OData service), because it just uses XmlHttpRequest under the covers.

Handling Network Connectivity (in Brief)

We’ll be covering network matters in Chapter 14, “Networking,” but there’s one important aspect that you should be aware of early in your development efforts. What does an app do with changes to network connectivity, such as disconnection, reconnection, and changes in bandwidth or cost (such as roaming into another provider area)?

The Windows.Networking.Connectivity APIs supply the details. There are three main ways to respond to such events:

• First, have a great offline story for when connectivity is lost: cache important data, queue work to be done later, and continue to provide as much functionality as you can without a connection. Clearly this is closely related to your overall state management strategy. For example, if network connectivity was lost while you were suspended, you might not be able to refresh your data at all, so be prepared for that circumstance! On the flip side, if you were offline when suspended, check for connectivity when resuming.

• Second, listen for network changes to know when connectivity is restored, and then process your queues, recache data, and so forth.

• Third, listen for network changes to be cost-aware on metered networks. Section 4.5 of the Windows 8 app certification requirements, in fact, deals with protecting consumers from “bill shock” caused by excessive data usage on such networks. The last thing you want, to be sure, are negative reviews in the Store on issues like this.

On a simpler note, be sure to test your apps with and without network connectivity to catch little oversights in your code. In Here My Am!, for example, my first versions of the script in html/map.html didn’t bother to check whether the remote script for Bing Maps had actually been downloaded. Now it checks whether the Microsoft namespace (for the Microsoft.Maps.Map constructor) is valid. In SimpleXhr too, I made sure to provide an error handler to the WinJS.xhr promise so that I could at least display a simple message. There’s much more you can do here, of course, but try to at least cover the basics to avoid exceptions that will terminate the app.

Tips and Tricks for WinJS.xhr

Without opening the whole can of worms that is XmlHttpRequest, it’s useful here to look at just a couple of additional points around WinJS.xhr.

First, notice that the single argument to this function is an object that can contain a number of properties. The url property is the most common, of course, but you can also set the type (defaults to “GET”) and the responseType for other sorts of transactions, supply user and password credentials, set headers (such as “If-Modified-Since” with a date to control caching), and provide whatever other additional data is needed for the request (such as query parameters for XHR to a database). You can also supply a customRequestInitializer function that will be called with the XmlHttpRequest object just before it’s sent, allowing you to perform anything else you need at that moment.

Second is setting a timeout on the request. You can use the customRequestInitializer for this purpose, setting the XmlHttpRequest.timeout property and possibly handling the ontimeout event. Alternately, as we’ll see in the “Completing the Promises Story” section at the end of this chapter, you can use the WinJS.Promise.timeout function, which allows you to set a timeout period after which the WinJS.xhr promise (and the async operation connected to it) will be canceled. Canceling is accomplished by simply calling a promise’s cancel method.

You might have need to wrap WinJS.xhr in another promise, something that we’ll also see at the end of this chapter. You could do this to encapsulate other intermediate processing with the XHR call while the rest of your code just uses the returned promise as usual. In conjunction with a timeout, this can also be used to implement a multiple retry mechanism.

Next, if you need to coordinate multiple XHR calls together, you can use WinJS.Promise.join, which we’ll again see later on.

We also saw how to process transferred bytes within the progress handler. You can use other data in the response and request as well. For example, the event args object contains a readyState property.

For Windows Store apps, using XHR with localhost: URI’s (local loopback) is blocked by design. During development, however, this is very useful to debug a service without deploying it. You can enable local loopback in Visual Studio by opening the project properties dialog (Project menu > <project> Properties…), selecting Debugging on the left side, and setting Allow Local Network Loopback to yes. We’ll see example of this in Chapter 13 where it’s very useful to debug services that issue tile updates and other notifications.

Finally, it’s helpful to know that for security reasons cookies are automatically stripped out of XHR responses coming into the local context. One workaround to this is to make XHR calls from a web context iframe (in which you can use WinJS.xhr) and then to extract the cookie information you need and pass it to the local context via postMessage. Alternately, you might be able to solve the problem on the service side, such as implementing an API there that will directly provide the information you’re trying to extract from the cookies in the first place.

For all other details on this function, refer to the WinJS.xhr documentation and its links to associated tutorials.

Page Controls and Navigation

Now we come to an aspect of Windows Store apps that very much separates them from typical web applications. In web applications, page-to-page navigation uses <a href> hyperlinks or setting document.location from JavaScript. This is all well and good; oftentimes there’s little or no state to pass between pages, and even when there is, there are well-established mechanisms for doing so, such as HTML5 sessionStorage and localStorage (which work just fine in Store apps).

This type of navigation presents a few problems for Store apps, however. For one, navigating to a wholly new page means a wholly new script context—all the JavaScript variables from your previous page will be lost. Sure, you can pass state between those pages, but managing this across an entire app likely hurts performance and can quickly become your least favorite programming activity. It’s better and easier, in other words, for client apps to maintain a consistent in-memory state across pages.

Also, the nature of the HTML/CSS rendering engine is such that a blank screen appears when switching pages with a hyperlink. Users of web applications are accustomed to waiting a bit for a browser to acquire a new page (I’ve found many things to do with an extra 15 seconds!), but this isn’t an appropriate user experience for a fast and fluid Windows Store app. Furthermore, such a transition doesn’t allow animation of various elements on and off the screen, which can help provide a sense of continuity between pages if that fits with your design.

So, although you can use direct links, Store apps typically implement “pages” by dynamically replacing sections of the DOM within the context of a single page like default.html, akin to how AJAX-based apps work. By doing so, the script context is always preserved and individual elements or groups of elements can be transitioned however you like. In some cases, it even makes sense to simply show and hide pages so that you can switch back and forth quickly. Let’s look at the strategies and tools for accomplishing these goals.

WinJS Tools for Pages and Page Navigation

Windows itself, and the app host, provide no mechanism for dealing with pages—from the system’s perspective, this is merely an implementation detail for apps to worry about. Fortunately, the engineers who created WinJS and the templates in Visual Studio and Blend worried about this a lot! As a result, they’ve provided some marvelous tools for managing bits and pieces of HTML+CSS+JS in the context of a single container page:

WinJS.UI.Fragments contains a low-level “fragment-loading” API, the use of which is necessary only when you want close control over the process (such as which parts of the HTML fragment get which parent). We won’t cover it in this book; see the documentation and the Loading HTML fragments sample.

WinJS.UI.Pages is a higher-level API intended for general use and is employed by the templates. Think of this as a generic wrapper around the fragment loader that lets you easily define a “page control”—simply an arbitrary unit of HTML, CSS, and JS—that you can easily pull into the context of another page as you do other controls.23 They are, in fact, implemented like other controls in WinJS (as we’ll see in Chapter 4), so you can declare them in markup, instantiate them with WinJS.UI.process[All], use as many of them within a single host page as you like, and even nest them. See Scenario 1 of the HTML Page controls sample for examples.

These APIs provide only the means to load and unload individual pages—they pull HTML in from other files (along with referenced CSS and JS) and attach the contents to an element in the DOM. That’s it. To actually implement a page-to-page navigation structure, we need two additional pieces: something that manages a navigation stack and something that hooks navigation events to the page-loading mechanism of WinJS.UI.Pages.

For the first piece, you can turn to WinJS.Navigation, which through about 150 lines of CS101-level code supplies a basic navigation stack. This is all it does. The stack itself is just a list of URIs on top of which WinJS.Navigation exposes state, location, history, canGoBack, and canGoForward properties. The stack is manipulated through the forward, back, and navigate methods, and the WinJS.Navigation object raises a few events—beforenavigate, navigating, and navigated—to anyone who wants to listen (through addEventListener).24

For the second piece, you can create your own linkage between WinJS.Navigation and WinJS.UI.Pages however you like. In fact, in the early stages of app development of Windows 8, even prior to the first public developer preview releases, people ended up writing just about the same boilerplate code over and over. In response, the team at Microsoft responsible for the templates magnanimously decided to supply a standard implementation that also adds some keyboard handling (for forward/back) and some convenience wrappers for layout matters. Hooray!

This piece is called the PageControlNavigator. Because it’s just a piece of template-supplied code and not part of WinJS, it’s entirely under your control, so you can tweak, hack, or lobotomize it however you want.25 In any case, because it’s likely that you’ll often use the PageControlNavigator in your own apps, let’s look at how it all works in the context of the Navigation App template.

Note Additional samples that demonstrate basic page controls and navigation, along with handling session state, can be found in the following SDK samples: App activate and suspend using WinJS (using the session state object in a page control), App activated, resume and suspend (described earlier; shows using the suspending deferral and restarting after termination), and Navigation and navigation history.

The Navigation App Template, PageControl Structure, and PageControlNavigator

Taking one step beyond the Blank App template, the Navigation App template demonstrates the basic use of page controls. (The more complex templates build navigation out further.) If you create a new project with this template in Visual Studio or Blend, here’s what you’ll get:

default.html Contains a single container div with a PageControlNavigator control pointing to pages/home/home.html as the app’s home page.

js/default.js Contains basic activation and state checkpoint code for the app.

css/default.css Contains global styles.

pages/home Contains a page control for the “home page” contents, composed of home.html, home.js, and home.css. Every page control typically has its own markup, script, and style files.

js/navigator.js Contains the implementation of the PageControlNavigator class.

To build upon this structure, add additional pages by using a page control template. I recommend first creating a new folder for the page under pages, like home in the default project structure. Then right-click that folder, select Add > New Item, and select Page Control. This will create suitably named .html, .js. and .css files in that folder.

Now let’s look at the body of default.html (omitting the standard header and a commented-out AppBar control):

<body>
    <div id="contenthost" data-win-control="Application.PageControlNavigator"
        data-win-options="{home: '/pages/home/home.html'}"></div>
</body>

All we have here is a single container div named contenthost (it can be whatever you want), in which we declare the Application.PageControlNavigator control. With this we specify a single option to identify the first page control it should load (/pages/home/home.html). The PageControlNavigator will be instantiated within our activated handler’s call to WinJS.UI.processAll.

Within home.html we have the basic markup for a page control. This is what the Navigation App template provides as a home page by default, and it’s pretty much what you get whenever you add a new PageControl from the item template:

<!DOCTYPE html>
<html>
<head>
    <!--... typical HTML header and WinJS references omitted -->
    <link href="/css/default.css" rel="stylesheet">
    <link href="/pages/home/home.css" rel="stylesheet">
    <script src="/pages/home/home.js"></script>
</head>
<body>
    <!-- The content that will be loaded and displayed. -->
    <div class="fragment homepage">
        <header aria-label="Header content" role="banner">
            <button class="win-backbutton" aria-label="Back" disabled></button>
            <h1 class="titlearea win-type-ellipsis">
                <span class="pagetitle">Welcome to NavApp!</span>
            </h1>
        </header>
        <section aria-label="Main content" role="main">
            <p>Content goes here.</p>
        </section>
    </div>
</body>
</html>

The div with fragment and homepage CSS classes, along with the header, creates a page with a standard silhouette and a back button, which the PageControlNavigator automatically wires up for keyboard, mouse, and touch events. (Isn’t that considerate of it!) All you need to do is customize the text within the h1 element and the contents within section, or just replace the whole smash with the markup you want. (By the way, even though the WinJS files are referenced in each page control, they aren’t actually reloaded; they exist here to help you edit a page control in Blend.)

The definition of the actual page control is in pages/home/home.js; by default, the templates just provide the bare minimum:

(function () {
    "use strict";

    WinJS.UI.Pages.define("/pages/home/home.html", {
        // This function is called whenever a user navigates to this page. It
        // populates the page elements with the app's data.
        ready: function (element, options) {
            // TODO: Initialize the page here.
        }
    });
})();

The most important part is WinJS.UI.Pages.define, which associates a relative URI (the page control identifier), with an object containing the page control’s methods. Note that the nature of define allows you to define different members of the page in multiple places; multiple calls to WinJS.UI.Pages.define with the same URI will simply add members to an existing definition, replacing those that already exist. Be mindful that if you have a typo in the URI, including a mismatch between the URI here and the actual path to the page, the page won’t load. This can be a subtle error to track down.

For a page created with the Page Control item template, you get a couple more methods in the structure (some comments omitted):

(function () {
    "use strict";

    WinJS.UI.Pages.define("/page2.html", {
        ready: function (element, options) {
        },

        updateLayout: function (element, viewState, lastViewState) {
            // TODO: Respond to changes in viewState.
        },

        unload: function () {
            // TODO: Respond to navigations away from this page.
        }
    });
})();

It’s good to note that once you’ve defined a page control in this way, you can instantiate it from JavaScript with new by first obtaining its constructor function from WinJS.UI.Pages.get(<page_uri>) and then calling that constructor with the parent element and an object containing its options.

Although a basic structure for the ready method is provided by the templates, WinJS.UI.Pages and the PageControlNavigator will make use of the following if they are available:

Image

Note that WinJS.UI.Pages calls the first four methods; the unload and updateLayout methods, on the other hand, are used only by the PageControlNavigator. Of all of these, the ready method is the most common one to implement. It’s where you’ll do further initialization of control (e.g., populate lists), wire up other page-specific event handlers, and so on. The unload method is also where you’ll want to remove event listeners for WinRT objects, as described in “WinRT Events and removeEvent- Listener” later on. The updateLayout method is important when you need to adapt your page layout to new conditions, such as changing the layout of a ListView control (as we’ll see in Chapter 5, “Collections and Collection Controls”).

As for the PageControlNavigator itself, the code in js/navigator.js shows how it’s defined and how it wires up a few events in its constructor:

(function () {
    "use strict";

    // [some bits omitted]
    var nav = WinJS.Navigation;

    WinJS.Namespace.define("Application", {
        PageControlNavigator: WinJS.Class.define(
        // Define the constructor function for the PageControlNavigator.
            function PageControlNavigator (element, options) {
                this.element = element || document.createElement("div");
                this.element.appendChild(this._createPageElement());

                this.home = options.home;
                nav.onnavigated = this._navigated.bind(this);
                window.onresize = this._resized.bind(this);

                document.body.onkeyup = this._keyupHandler.bind(this);
                document.body.onkeypress = this._keypressHandler.bind(this);
                document.body.onmspointerup = this._mspointerupHandler.bind(this);
            }, {
    //...

First we see the definition of the Application namespace as a container for the PageControl-Navigator class. Its constructor receives the element that contains it (the contenthost div in default.html), or it creates a new one if none is given. The constructor also receives the options declared in the data-win-options attribute of that element. The page control then appends its contents to this root element, adds a listener for the WinJS.Navigation.onnavigated event, and sets up listeners for keyboard, mouse, and resizing events. It then waits for someone to call WinJS.Navigation.navigate, which happens in the activated handler of js/default.js, to navigate to either the home page or the last page viewed if previous session state was reloaded:

if (app.sessionState.history) {
    nav.history = app.sessionState.history;
}
args.setPromise(WinJS.UI.processAll().then(function () {
    if (nav.location) {
        nav.history.current.initialPlaceholder = true;
        return nav.navigate(nav.location, nav.state);
    } else {
        return nav.navigate(Application.navigator.home);
    }
}));

When that happens, the PageControlNavigator’s _navigated handler is invoked, which in turn calls WinJS.UI.Pages.render to do the loading, the contents of which are then appended as child elements to the navigator control:

_navigated: function (args) {
    var that = this;
    var newElement = that._createPageElement();
    var parentedComplete;
    var parented = new WinJS.Promise(function (c) { parentedComplete = c; });

    args.detail.setPromise(
        WinJS.Promise.timeout().then(function () {
            if (that.pageElement.winControl && that.pageElement.winControl.unload) {
                that.pageElement.winControl.unload();
            }
            return WinJS.UI.Pages.render(args.detail.location, newElement,
                args.detail.state, parented);
        }).then(function parentElement(control) {
            that.element.appendChild(newElement);
            that.element.removeChild(that.pageElement);
            that.navigated();
            parentedComplete();
        })
    );
},

Here you can see how the PageControlNavigator calls the previous page’s unload event. After this, the new page’s content is added to the DOM, and then the old page’s contents are removed. The call to that.navigated will then reset this.element.

Tip In a page control’s JavaScript code you can use this.element.querySelector rather than document.querySelector if you only want to look in the page control’s contents and have no need to traverse the entire DOM. Because this.element is just a node, however, it does not have other traversal methods like getElementById.

And that, my friends, is how it works! In addition to the HTML Page controls sample, and to show a concrete example of doing this in a real app, the code in the HereMyAm3d sample has been converted to use this model for its single home page. To make this conversion, I started with a new project using the Navigation App template to get the page navigation structures set up. Then I copied or imported the relevant code and resources from HereMyAm3c, primarily into pages/home/home.html, home.js, and home.css. And remember how I said that you could open a page control directly in Blend (which is why pages have WinJS references)? As an exercise, open this project in Blend. You’ll first see that everything shows up in default.html, but you can also open home.html by itself and edit just that page.

You should note that WinJS calls WinJS.UI.processAll in the process of loading a page control, so we don’t need to concern ourselves with that detail. On the other hand, reloading state when previousExecutionState==terminated needs some attention. Because this is picked up in the WinJS.Application.onactivated event before any page controls are loaded and before the PageControlNavigator is even instantiated, we need to remember that condition so that the home page’s ready method can later initialize itself accordingly from app.sessionState values. For this we simply write another flag into app.sessionState called initFromState (true if previous-ExecutionState is terminated, false otherwise.)

WinJS.Namespace.define provides a shortcut for the JavaScript namespace pattern. This helps to minimize pollution of the global namespace as each app-defined namespace is just a single object in the global namespace but can provide access to any number of other objects, functions, and so on. This is used extensively in WinJS and is recommended for apps as well, where you define everything you need in a module—that is, within a (function() { ... })() block—and then export selective variables or functions through a namespace. In short, use a namespace anytime you’re tempted to add any global objects or functions!

The syntax: var ns = WinJS.Namespace.define(<name>, <members>) where <name> is a string (dots are OK) and <members> is any object contained in { }’s. Also, WinJS.Namespace.-defineWithParent(<parent>, <name>, <members>) defines one within the <parent> namespace.

If you call WinJS.Namespace.define for the same <name> multiple times, the <members> are combined. Where collisions are concerned, the most recently added members win. For example:

   WinJS.Namespace.define("MyNamespace", { x: 10, y: 10 });
   WinJS.Namespace.define("MyNamespace", { x: 20, z: 10 });
   //MyNamespace == { x: 20, y: 10, z: 10}

WinJS.Class.define is, for its part, a shortcut for the object pattern, defining a constructor so that objects can be instantiated with new.

Syntax: var className = WinJS.Class.define(<constructor>, <instanceMembers>, <staticMembers>) where <constructor> is a function, <instanceMembers> is an object with the class’s properties and methods, and <staticMembers> is an object with properties and methods that can be directly accessed via <className>.<member> (without using new).

Variants: WinJS.Class.derive(<baseClass>, ...) creates a subclass (... is the same arg list as with define) using prototypal inheritance, and WinJS.Class.mix(<constructor>, [<classes>]) defines a class that combines the instance (and static) members of one or more other <classes> and initializes the object with <constructor>.

Finally, note that because class definitions just generate an object, WinJS.Class.define is typically used inside a module with the resulting object exported to the rest of the app as a namespace member. Then you can use new <namespace>.<class> anywhere in the app.

In Windows Store apps you might encounter certain markup structures within code comments, often starting with a triple slash, ///. These are used by Visual Studio and Blend to provide rich IntelliSense within the code editors. You’ll see, for example, /// <reference path…/> comments, which create a relationship between your current script file and other scripts to resolve externally defined functions and variables. This is explained on the JavaScript IntelliSense page in the documentation. For your own code, especially with namespaces and classes that you will use from other parts of your app, use these comment structures to describe your interfaces to IntelliSense. For details, see Extending JavaScript IntelliSense, and look around the WinJS JavaScript files for many examples.

The Navigation Process and Navigation Styles

Having seen how page controls, WinJS.UI.Pages, WinJS.Navigation, and the PageControlNavigator all relate, it’s straightforward to see how to navigate between multiple pages within the context of a single HTML page (e.g., default.html). With the PageControlNavigator instantiated and a page control defined via WinJS.UI.Pages, simply call WinJS.Navigation.navigate with the relative URI of that page control (its identifier). This loads that page and adds it to the DOM inside the element to which the PageControlNavigator is attached, unloading any previous page. This makes that page visible, thereby “navigating” to it so far as the user is concerned. You can also use the other methods of WinJS.-Navigation to move forward and back in the nav stack, with its canGoBack and canGoForward properties allowing you to enable/disable navigation controls. Just remember that all the while, you’ll still be in the overall context of your host page where you created the PageControlNavigator control.

As an example, create a new project using the Grid App template and look at these particular areas:

pages/groupedItems/groupedItems is the home or “hub” page. It contains a ListView control (see Chapter 5) with a bunch of default items.

• Tapping a group header in the list navigates to section page (pages/groupDetail). This is done in pages/groupedItems/groupedItems.html, where an inline onclick handler event navigates to pages/groupDetail/groupDetail.html with an argument identifying the specific group to display. That argument comes into the ready function of pages/groupDetail/groupDetail.js.

• Tapping an item on the hub page goes to detail page (pages/itemDetail). The itemInvoked handler for the items, the _itemInvoked function in pages/groupedItems/groupedItem.js, calls WinJS.Navigation.navigate("/pages/itemDetail/itemDetail.html") with an argument identifying the specific item to display. As with groups, that argument comes into the ready function of pages/itemDetail/itemDetail.js.

• Tapping an item in the section page also goes to the details page through the same mechanism—see the _itemInvoked function in pages/groupDetail/groupDetail.js.

• The back buttons on all pages are wired into WinJS.Navigation.back by virtue of code in the PageControlNavigator.

For what it’s worth, the Split App template works similarly, where each list item on pages/items is wired to navigate to pages/split when invoked.

In any case, the Grid App template also serves as an example of what we call the Hub-Section-Detail navigation style. Here the app’s home page is the hub where the user can explore the full extent of the app. Tapping a group header navigates to a section, the second level of organization where only items from that group are displayed. Tapping an item (in the hub or in the section) navigates to a details page for that item. You can, of course, implement this navigation style however you like; the Grid App template uses page controls, WinJS.Navigation, and the PageControlNavigator. (Semantic zoom, as we’ll see in Chapter 5, is also supported as a navigation tool to switch between hubs and sections.)

An alternate navigation choice is the Flat style, which simply has one level of hierarchy. Here, navigation happens to any given page at any time through a navigation bar (swiped in along with the app bar, as we’ll see in Chapter 7, “Commanding UI”). When using page controls and PageControl-Navigator, navigation controls can just invoke WinJS.Naviation.navigate for this purpose. Note that in this style, there typically is no back button.

These styles, along with many other UI aspects of navigation, can be found on Navigation design for Windows Store apps. This is an essential topic for designers.

Some apps might require either a login or acceptance of a license agreement to do anything, and thus it’s appropriate that such pages are the first to appear in an app after the splash screen. In these cases, if the user does not accept a license or doesn’t provide a login, the app should display a message describing the necessity of doing so, but it should always leave it to the user to close the app if desired. Do not close the app automatically.

Typically, such pages appear only the first time the app is run. If the user provides a valid login, those credentials can be saved for later use via the Windows.Security.Credentials.-PasswordVault API. If the user accepts a EULA, that fact should be saved in appdata and reloaded anytime the app needs to check. These settings (login and acceptance of a license) should then always be accessible through the app’s Settings charm. Legal notices, by the way, as well as license agreements, should always be accessible through Settings as well. See Guidelines and checklist for login controls.

Optimizing Page Switching: Show-and-Hide

Even with page controls, there is still a lot going on when navigating from page to page: one set of elements is removed from the DOM, and another is added in. Depending on the pages involved, this can be an expensive operation. For example, if you have a page that displays a list of hundreds or thousands of items, where tapping any item goes to a details page (as with the Grid App template), hitting the back button from a detail page will require reconstruction of the list.

Showing progress indicators can help alleviate the user’s anxiety, and the recommendation is to show such indicators after two seconds and provide a means to cancel the operation after ten seconds. Even so, users are notoriously impatient and will likely want to quickly switch between a list of items and item details. In this case, page controls might not be the best design.

You could use a split (master-detail) view, of course, but that means splitting the screen real estate. An alternative is to actually keep the list page fully loaded the whole time. Instead of navigating to the item details page in the way we’ve seen, simply render that details page (see WinJS.UI.Pages.render) into another div that occupies the whole screen and overlays the list, and then make that div visible. When you dismiss the details page, just hide the div and set innerHTML to "". This way you get the same effect as navigating between pages but the whole process is much quicker. You can also apply WinJS animations like enterContent and exitContent to make the transition more fluid.

Note that because the PageControlNavigator is provided by the templates as part of your app, you can modify it however you like to provide this kind of capability in a more structured manner.

WinRT Events and removeEventListener

As we’ve already been doing in this book, typical practice within HTML and JavaScript, especially for websites, is to call addEventListener to specify event handlers or is to simply assign an event handler to an on<event> property of some object. Oftentimes these handlers are just declared as inline anonymous functions:

var myNumber = 1;
element.addEventListener(<event>, function (e) { myNumber++; } );

Because of JavaScript’s particular scoping rules, the scope of that anonymous function ends up being the same as its surrounding code, which allows the code within that function to refer to local variables like myNumber in the code above.

To ensure that such variables are available to that anonymous function when it’s later invoked as an event handler, the JavaScript engine creates a closure, a data structure that describes the local variables available to that function. Usually the closure is a small bit of memory, but depending on the code inside that event handler, the closure could encompass the entire global namespace—a rather large allocation!

Every such closure increases the memory footprint or working set of the app, so it’s a good practice to keep them at a minimum. For example, declaring a separate named function—which has its own scope—will reduce any necessary closure.

More important than minimizing closures is making sure that the event listeners themselves—and their associated closures—are properly cleaned up and their memory allocations released.

Typically, this is not even something you need to think about. When object such as HTML elements are destroyed, such as when a page control is unloaded from the DOM, their associated listeners are automatically removed and closures are released. However, in a Windows Store app written in HTML and JavaScript, there are other sources of events for which the app might add event listeners, where those objects are never destroyed. These can be objects from WinJS, objects from WinRT, and window and document. Those listeners must be cleaned up properly, or else the app will have memory leaks (memory that is allocated but never freed because it’s never released for garbage collection).

Of special concern are events that originate from WinRT objects. Because of the nature of the projection layer that makes WinRT available in JavaScript, WinRT ends up holding references to JavaScript event handlers (known also as delegates) while the JavaScript closures hold references to those WinRT objects. As a result of these cross-references, those closures might never be released.

This is not a problem, mind you, if the app always listens to a particular event. For example, the suspending and resuming events are two that an app typically listens to for its entire lifetime, so any related allocations will be cleaned up when the app is terminated. The same is true for most listeners you might add for window and document events, which persist for the lifetime of the app.

Memory leaks occur, however, when an app listens to a WinRT object event only temporarily and neglects to explicitly call removeEventListener, or when the app might call addEventListener for the same event multiple times (in which case you can end up duplicating closures). With page controls, as discussed in this chapter, it’s common to call addEventListener within the page’s ready method on some WinRT object. When you do this, be sure to match that call with removeEventListener in the page’s unload method to release the closures. I’ve done this in HereMyAm3d with datarequested in pages/home/home.js just to be clear.

Throughout this book, the WinRT events with which you need to be concerned are highlighted with a special color, as in datarequested (except where the text is also a hyperlink). This is your cue to check whether an explicit call to removeEventListener is necessary. Again, if you’ll always be listening for the event, removing the listener isn’t needed, but if you add a listener when loading a page control, you almost certainly will need to make that extra call. Be especially aware that the samples don’t necessary pay attention to this detail, so don’t follow any examples of neglect there. Finally, note that events from WinJS objects don’t need this attention because the library already handles removal of event listeners.

In the chapters that follow, I will remind you of what we’ve just discussed on our first meaningful encounter with a WinRT event. Keep your eyes open for the color coding in any case.

Completing the Promises Story

Whew! We’ve taken a long ride in this chapter through many, many fine details of how apps are built and how they run (or don’t run!). One consistent theme you may have noticed is that of promises—they’ve come up in just about every section! Indeed, async abounds within both WinJS and WinRT, and thus so do promises.

I wanted to close this chapter, then, by flushing out the story of promises, for they provide richer functionality than we’ve utilized so far. Demonstrations of what we’ll cover here can be found in the WinJS Promise sample, and if you want the fuller async story, read Keeping apps fast and fluid with asynchrony in the Windows Runtime on the Windows 8 developer blog.

In review, let’s step back for a moment to revisit what a promise really means. Simply said, it’s an object that returns a value, simple or complex, sometime in the future. The way you know when that value is available is by calling the promise’s then or done method with a completed handler. That handler will be called with the promised value (the result) when it is ready—which will be immediately if the value is already available! Furthermore, you can call then/done multiple times for the same promise, and you’ll just get the same result in each completed handler. This won’t cause the system to get confused or anything.

If there’s an error along the way, the second parameter to then/done is an error handler that will be called instead of the completed handler. Otherwise exceptions are swallowed by then or thrown to the event loop by done, as we’ve discussed.

A third parameter to then/done is a progress handler, which is called periodically by those async operations that support it.26 We’ve already seen, for instance, how WinJS.xhr operations will periodically call the progress function for “ready state” changes and as the response gets downloaded.

Now there’s no requirement that a promise has to wrap an async operation or async anything. You can, in fact, wrap any value in a promise by using the static method WinJS.Promise.wrap. Such a wrapper on an already existing value (the future is now!) will just turn right around and call the completed handler with that value as soon as you call then or done. This allows you to use any value where a promise is expected, or return things like errors from functions that otherwise return promises for async operations. WinJS.Promise.wraperror exists for this specific purpose.

WinJS.Promise also provides a host of useful static methods, called directly through WinJS.Promise rather than through a specific promise instance:

is determines whether an arbitrary value is a promise, It basically makes sure it’s an object with a function named “then”; it does not test for “done”.

as works like wrap except that if you give it a promise, it just returns that promise. If you give a promise to wrap, it wraps it in another promise.

join aggregates promises into a single one that’s fulfilled when all the values given to it, including other promises, are fulfilled. This essentially groups promises with an AND operation (using then, so you’ll want to call the join’s done method to handle errors appropriately).

any is similar to join but groups with an OR (again using then).

cancel stops an async operation. If an error function is provided, it’s called with a value of Error("canceled").

theneach applies completed, error, and progress handlers to a group of promises (using then), returning the results as another group of values inside a promise.

timeout has a dual nature. If you just give it a timeout value, it returns a promise wrapped around a call to setTimeout. If you also provide a promise as the second parameter, it will cancel that promise if it’s not fulfilled within the timeout period. This latter case is essentially a wrapper for the common pattern of adding a timeout to some other async operation that doesn’t have one already.

addEventListener/removeEventListener (and dispatchEvent) manage handlers for the error event that promises will fire on exceptions (but not for cancellation). Listening for this event does not affect use of error handlers. It’s an addition, not a replacement.27

In addition to using functions like as and wrap, you can also create a promise from scratch by using new WinJS.Promise(<init> [, <oncancel>). Here <init> is a function that accepts completed, error, and progress dispatchers, and oncancel is an optional function that’s called in response to WinJS.Promise.cancel. The dispatchers are what you call to trigger any completed, error, or progress handlers given to the promise’s then or done methods, whereas oncancel is your own function that the promise will call if it’s canceled. Creating a new promise in this way is typically done when you create an async function of your own. For example, we’ll see how this is used to encapsulate an async web worker in Chapter 16, “WinRT Components.”

Also, if WinJS.Promise.as doesn’t suffice, creating a promise like this is useful to wrap other operations (not just values) within the promise structure so that it can be chained or joined with other promises. For example, if you have a library that talks to a web service through raw async XmlHttpRequest, you can wrap each API of that library with promises. You might also use a new promise to combine multiple async operations (or other promises!) from different sources into a single promise, where join or any don’t give you the control you need. Another example is encapsulating specific completed, error, and progress functions within a promise, such as to implement a multiple retry mechanism on top of singular XHR operations, to hook into a generic progress updater UI, or to add under-the-covers logging or analytics with service calls so that the rest of your code never needs to know about them.

What We’ve Just Learned

• How the local and web contexts affect the structure of an app, for pages, page navigation, and iframe elements.

• How to use application content URI rules to extend resource access to web content in an iframe.

• Using ms-appdata URI scheme to reference media content from local, roaming, and temp appdata folders.

• How to execute a series of async operations with chained promises.

• How exceptions are handled within chained promises and the differences between then and done.

• Methods for getting debug output and error reports for an app, within the debugger and the Windows Event Viewer.

• How apps are activated (brought into memory) and the events that occur along the way.

• The structure of app activation code, including activation kinds, previous execution states, and the WinJS.UI.Application object.

• Using extended splash screens when an app needs more time to load, and deferrals when the app needs to use async operations on startup.

• The important events that occur during an app’s lifetime, such as focus events, visibility changes, view state changes, and suspend/resume/terminate.

• The basics of saving and restoring state to restart after being terminated, and the WinJS utilities for implementing this.

• Using data from services through WinJS.xhr and how this relates to the resuming event.

• How to achieve page-to-page navigation within a single page context by using page controls, WinJS.Navigation, and the PageControlNavigator from the Visual Studio/Blend templates, such as the Navigation App template.

• All the details of promises that are common used with, but not limited to, async operations.