Chapter 8
State, Settings, Files, and Documents

It would be very interesting when you travel if every hotel room you stayed in was automatically configured exactly as how you like it—the right pillows and sheets, the right chairs, the right food in the minibar rather than atrociously expensive and obscenely small snack tins. If you’re sufficiently wealthy, of course, you can send people ahead of you to arrange such things, but such luxury remains naught but a dream for most of us.

Software isn’t bound by such limitations, fortunately. Sending agents on ahead doesn’t involve booking airfare for them, providing for their income and healthcare, and contributing to their retirement plans. All it takes is a little connectivity, some cloud services, and voila! All of your settings can automatically travel with you—that is, between the different devices you’re using.

This roaming experience, as it’s called, is built right into Windows 8 for systemwide settings such as your profile picture, start screen preferences, Internet favorites, your desktop theme, saved credentials, and so forth. When you use a Microsoft account to log into Windows on a trusted PC, these settings are securely stored in the cloud and automatically transferred to other trusted Windows 8 devices where you use the same account. I was pleasantly surprised during the development of Windows 8 that I no longer needed to manually transfer all this data when I updated my machine from one release preview to another!

With such an experience in place for system settings, users will expect similar behavior from apps: they will expect that app-specific settings on one device will appropriately roam to the same app installed on other devices. I say “appropriately” because some settings don’t make sense to roam, especially those that are particular to the hardware in the device. On the other hand, if I configure email accounts in an app on one machine, I would certainly hope those show up on others! (I can’t tell you how many times I’ve had to set up my four active email accounts in Outlook.) In short, as a user I’ll expect that my transition between devices—on the system level and the app level—is both transparent and seamless.

This means, then, that each app must do its part to manage its state, deciding what information is local to a device, what data roams between devices (including roaming documents and other user data through services like SkyDrive), and even what kinds of caching can help improve performance and provide an good offline experience. As I’ve said with many such functional aspects, the effort you invest in these can make a real difference in how users perceive your app and the ratings and reviews they’ll give it in the Windows Store.

Many such settings will be completely internal to an app, but others can and should be directly configurable by the user. In the past, this has given rise to an oft-bewildering array of nested dialog boxes with multiple tabs, each of which is adorned with buttons, popup menus, and long hierarchies of check boxes and radio buttons. As a result, there’s been little consistency in how apps are configured. Even a simple matter of where such options are located has varied between Tools/Options, Edit/Preferences, and File/Info commands, among others!

Fortunately, the designers of Windows 8 recognized that most apps have settings of some kind, so they included Settings on the Charms bar alongside the other near-ubiquitous search, share, and device functions. For one thing, this eliminates the need for users to remember where a particular app’s settings are located, and apps don’t need to wonder how, exactly, to integrate settings into their overall content flow and navigation hierarchy. That is, by being placed in the Settings charm, settings are effectively removed from an app’s content structure, thereby simplifying the app’s overall design. The app needs only to provide distinct pages that are displayed when the user invokes the charm.

Clearly, then, an app’s state and its Settings UI are intimately connected, as we will see in this chapter. We’ll also have the opportunity to look at the storage and file APIs in WinRT, along with some of the WinJS file I/O helpers and other storage options like IndexedDB.

Of course, app data—settings and internal state—is only one part of the story. User data—such as documents, pictures, music/audio, and videos—is equally important. For these we’ll look at the various capabilities in the manifest that allow an app to work with document and media libraries, as well as removable storage, how to enumerate folder contents with queries, and how the file picker lets the user give consent to other safe areas of the file system (but not system areas and the app data folders of other apps).

Here, too, Windows 8 actually takes us beyond the local file system. The vast majority of data to which a user has access today is not local to their machine but lives online. The problem here has been that such data is typically buried behind the API of a web service, meaning that the user has to manually use a web app to browse data, download and save it to the local file system, and then import it into another app. Seeing this pattern, the Windows 8 designers found another opportunity to introduce a new level of integration and consistency, allowing apps to surface back-end data such that it appears as part of the local file system to other apps. This happens through the file picker contracts, bringing users a seamless experience across local and online data. Here we’ll see the consumer side of the story, saving the provider side for Chapter 12, “Contracts.”

In short, managing state and providing access to user data, wherever it’s located, is one of the most valuable features that apps can provide, and it goes a long way to helping consumers feel that your app is treating them like they truly matter.

The Story of State

To continue the analogy started in this chapter’s introduction, when we travel to new places and stay in hotels, most of us accept that we’ll spend a little time upon arrival unpacking our things and setting up the room to our tastes. On the other hand, we expect the complete opposite from our homes: we expect continuity or statefulness. Having moved twice in the last year myself (once to a temporary home while our permanent home was being completed), I can very much appreciate the virtues of statefulness. Imagine that everything in your home got repacked into boxes every time you left, such that you had to spend hours, days, or weeks unpacking it all again! No, home is the place where we expect things to stay put, even if we do leave for a time. I think this exactly why many people enjoy traveling in a motor home!

Windows Store apps are intended to be similarly stateful, meaning that they maintain a sense of continuity between sessions, even if the app is suspended and terminated along the way. In this way, apps feel more like a home than a temporary resting place; they become a place where users come to relax with the content they care about. So, the less work they need to do to start enjoying that experience, the better.

An app’s state is central to this experience because it has a much longer lifetime than the app itself. State persists, as it should, when an app isn’t running and can also persist between different versions of the app. The state version is, in fact, managed separately from the app version.

To clearly understand app state, let’s first briefly revisit user data again. User data like documents, pictures, music, videos, playlists, and other such data are created and consumed by an app but not dependent on the app itself. User data implies that any number of apps might be able to load and manipulate such data, and such data always remains on a system irrespective of the existence of apps. For this reason, user data itself isn’t really part of an app’s state. That is, while the paths of documents and other files might be remembered as the current file, in the user’s favorites, or in a recently used list, the actual contents of those files aren’t part of that state. User data, then, doesn’t have a strong relationship to app lifecycle events either. It’s either saved explicitly through a user-invoked command or implicitly on events like visibilitychange rather than suspending. Again, the app might remember which file is currently loaded as part of its session state during suspending, but the file contents itself should be saved outside of this event since you have only five seconds to complete whatever work is necessary.

In contrast to user data, app data is comprised of everything an app needs to run and maintain its statefulness. App data is also maintained on a per-user basis, is completely tied to the existence of a specific app, and is accessible by that app exclusively. As we’ve seen earlier in this book, app data is stored in user-specific folders that are wholly removed from the file system when an app is uninstalled. For this reason, never store anything in app data that the user might want outside your app. It also makes sense to avoid using document and media libraries to store state that wouldn’t continue to be meaningful to the user if the app is uninstalled.

App data is used to manage the following kinds of state:

Session state The state that an app saves when being suspended to restore it after a possible termination. This includes form data, the page navigation history, and so forth. As we saw in Chapter 3, “App Anatomy and Page Navigation,” being restarted after being suspended and terminated is the only case in which an app restores session state. Session state is typically saved incrementally (as the state changes) or within the suspending or checkpoint event.

Local app state Those settings that are typically loaded when an app is launched. App state includes cached data, saved searches, lists of recently viewed items, and various behavioral settings that appear in the Settings panel like display units, preferred video formats, device-specific configurations, and so on. Local app state is typically saved when it’s changed since it’s not directly tied to lifecycle events.

Roaming app state App state that is shared between the same app running on multiple Windows 8 devices where the same user is logged in, such as favorites, viewing position within videos, account configurations, URIs for important files on cloud storage locations, perhaps some saved searches or queries, etc. Like local app state, these might be manipulated through the Settings panel. Roaming state is also best saved when values are changed; we’ll see more details on how this works later.

There are two other components of app state that are actually managed separately from app data folders and settings containers. One is the list of those files originally obtained through file pickers to which the app would like to have programmatic access in the future. For these files you cannot just save the pathname—you must also save the fact that the user granted permission through the file picker. This is the purpose of the Windows.Storage.AccessCache APIs, and is essentially part of local state.

The other part is credentials that you’ve collected from a user and would like to retrieve in the future. Because this is a critical security concern, an app should never directly save credentials in its own app data. Instead, use the credential locker API in Windows.Security.Credentials.PasswordVault. The contents of the locker will be roamed between a user’s trusted PCs, so this constitutes part of roaming app state. We’ll see more of this API in Chapter 14, “Networking.”

Settings and State

App state may or may not be surfaced directly to the user. Many bits of state are tracked internally within the app or, like a navigation history, might reflect user activity but aren’t otherwise presented directly to the user. Other pieces of state, like preferences, accounts, profile pictures, and so forth, can and should be directly exposed to the user, which is the purpose of the Settings charm.

What appears in the Settings charm for an app should be those settings that affect behavior of the app as a whole and are adjusted only occasionally. State that applies only to particular pages or workflows should not appear in Settings: they should be placed directly on the page (the app canvas) or in the app bar, as we’ve seen in Chapter 7, “Commanding UI.” All of these things still comprise app state and are managed as such, but not everything is appropriate for Settings.

Some examples of good candidates for the Settings charm are as follows:

• Display preferences like units, color themes, alignment grids, and defaults.

• Roaming preferences that allow the user to customize the app’s overall roaming experience, such as to keep configurations for personal and work machines separate.

• Account and profile configurations, along with commands to log in, log out, and otherwise manage those accounts and profiles. Passwords should never be stored directly or roamed, however; use the Credential Locker instead.

• Behavioral settings like online/offline mode, auto-refresh, refresh intervals, preferred video/audio streaming quality, whether to transfer data over metered network connections, the location from which the app should draw data, and so forth.

• A feedback link where you can gather specific information from the user.

• Additional information about the app, such as Help, About, a copyright page, a privacy statement, license agreements, and terms of use. Oftentimes these commands will take the user to a separate website, which is perfectly fine.

I highly recommend that you run the apps that are built into Windows and explore their use of the Settings charm. You’re welcome to explore how Settings are used by other apps in the Store as well, but those might not always follows the design guidelines as consistently—and consistency is essential to settings!

Speaking of which, Windows automatically provides commands called Permissions and Rate and Review for all apps. Rate and Review takes the user to the product page in the Windows Store where he or she can, of course, provide a rating and write a review. Permissions, for its part, allows the user to control the app’s access to sensitive capabilities like geolocation, the camera, the microphone, and so forth. What appears here is driven by the capabilities declared in the app manifest, and it’s where the user can go to revoke or grant consent for those capabilities. Of course, if the app uses no such capabilities, Permissions doesn’t appear.

You might have noticed that I’ve made no mention of showing app updates within Settings. This is specifically discouraged because update notices are provided through the Windows Store directly. This is another way of reducing the kinds of noise with which users have had to contend with in the past, with each app presenting its updates in different ways (and sometimes far too often!).

App Data Locations

Now that we understand what kinds of information make up app state, the next question is, Where is it stored? You might remember from Chapter 1, “The Life Story of an App,” that when Windows installs an app for a user (and all Windows Store apps are accessible to only the user who installed them), it automatically creates LocalState, TempState, and RoamingState folders within the current user’s AppData folder, which are the same ones that get deleted when you uninstall an app. On the file system, if you point Windows Explorer to %localappdata%\packages, you’ll see a bunch of folders for the different apps on your system. If you navigate to any of these, you’ll see these folders along with one called “Settings,” as shown in Figure 8-1 for the built-in Sports app. The figure also shows the varied contents of these folders.

images

FIGURE 8-1 The Sports app’s AppData folders and their contents.

In the LocalState folder of Figure 8-1 you can see a file named _sessionState.json. This is the file where WinJS saves and loads the contents of the WinJS.Application.sessionState object as we saw in Chapter 3. Since it’s just a text file in JSON format, you can easily open it in Notepad or some other JSON viewer to examine its contents. In fact, if you look open this file for the Sports app, as is shown in the figure, you’ll see a value like {"lastSuspendTime":1340057531501}. The Sports app (along with News, Weather, etc.) show time-sensitive content, so they save when they were suspended and check elapsed time when they’re resumed. If that time exceeds their refresh intervals, they can go get new data from their associated service. In the case of the Sports app, one of its Settings specifically lets the user set the refresh period.

If your app uses any of the HTML5 storage APIs, like local storage, IndexedDB, and app cache, their data will also appear within the LocalState folder.

Note If you look carefully at Figure 8-1, you’ll see that all the app data–related folders, including roaming, are in the user’s overall AppData/Local folder. There is also a sibling AppData/Roaming folder, but this applies only to roaming user account settings on intranets, such as when a domain-joined user logs in to another machine on a corporate network. This AppData/Roaming folder has no relationship to the AppData/Local…/RoamingState folder for Windows Store apps.

Programmatically, you can refer to these locations in several ways. First, you can use the ms-appdata:/// URI scheme as we saw in Chapter 3, where ms-appdata:///local, ms-appdata:///roaming, and ms-appdata:///temp refer to the individual folders and their contents. (Note the triple slashes, which is a shorthand allowing you to omit the package name.) You can also use the object returned from the Windows.Storage.ApplicationData.current method, which contains all the APIs you need to work with state.

By the way, you might have some read-only state directly in your app package. With URIs, you can just use relative paths that start with /. If you want to open and read file contents directly, you can use the StorageFolder object from the Windows.ApplicationModel.Package.current.installedLocation property. We’ll come back to the StorageFolder class shortly.

AppData APIs (WinRT and WinJS)

When you ask Windows for the Windows.Storage.ApplicationData.current property, what you get is a Windows.Storage.ApplicationData object that is completely configured for your particular app. This object contains the following:

localFolder, temporaryFolder, and roamingFolder Each of these properties is a Windows.Storage.StorageFolder object that allows you to create whatever files and additional folder structures you want in these locations (but note the roamingStorageQuota below).

localSettings and roamingSettings These properties are Windows.Storage.Appli-cationDataContainer objects that provide for managing a hierarchy of key-value settings pairs or composite groups of such pairs. All these settings are stored in the appdata Settings folder in the settings.dat file.

roamingStorageQuota This property contains the number of kilobytes that Windows will automatically roam for the app (typically 100); if the total data stored in roamingFolder and roamingSettings exceeds this amount, roaming will be suspended until the amount falls below the quota. You have to track how much data you store yourself if you think you’re near the limit.

dataChanged An event indicating the contents of the roamingFolder or roaming-Settings have been synchronized from the cloud; an app should re-read roaming state in this case. This is a WinRT event for which you need to use removeEventListener as described in Chapter 3 in the “WinRT Events and removeEventListener” section.

signalDataChanged A method that triggers a dataChanged event. This allows you to consolidate local and roaming updates in a single handler for the dataChanged event.

version property and setVersionAsync method These provide for managing the version stamp on your app data. This version applies to the whole of your app data, local, temp, and roaming together; there are not separate versions for each.

clearAsync A method that clears out the contents of all AppData folders and settings containers. Use this when you want to reinitialize your default state, which can be especially helpful if you’ve restarted the app because of corrupt state.

clearAsync(<locality>) A variant of clearAsync that is limited to one locality (local, temp, and roaming). The locality is identified with a value from Windows.Storage.Application-DataLocality, such as Windows.Storage.ApplicationDataLocality.local. In the case of local and roaming, the contents of both the folders and settings containers are cleared; temp affects only the TempState folder.

Let’s now see how to use the API here to manage the different kinds of app data, which includes a number of WinJS helpers for the same purpose.

Hint The APIs that work with app state will generate events in the Event Viewer if you’ve enabled the channel as described in Chapter 3 in the “Debug Output, Error Reports, and the Event Viewer” section. Again, make sure that View > Show Analytics and Debug Logs is checked on the menu. Then navigate to Application and Services Log, and expand Microsoft/Windows/AppModel-State, where you’ll find Debug and Diagnostic groups.

Settings Containers

For starters, let’s look at the localSettings and roamingSettings properties, which are typically referred to as settings containers. You work with these through the ApplicationDataContainer API, which is relatively simple. Each container has four read-only properties: a name (a string), a locality (again from Windows.Storage.ApplicationDataLocality, with local and roaming being the only values here), and collections called values and containers.

The top-level settings containers have empty names; the property will be set for child containers that you create with the createContainer method (and remove with deleteContainer). Those child containers can have other containers as well, allowing you to create a whole settings hierarchy. That said, these settings containers are intended to be used for small amounts of data, typically user settings; any individual setting is limited to 8K and any composite setting (see below) to 64K. With these limits, going beyond about a megabyte of settings implies a somewhat complex hierarchy, which will be difficult to manage and will certainly slow to access. So don’t be tempted to think of app data settings as a kind of database; other mechanisms like IndexedDB and SQLite are much better suited for that purpose, and you can write however much data you like as files in the various AppData folders (remembering the roaming limit when you write to roamingFolder).

For whatever container you have in hand, its containers collection is an IMapView object through which you can enumerate its contents. The values collection, on the other hand, is just an array (technically an IPropertySet object in WinRT, which is projected into JavaScript as an array with IPropertySet methods). So, although the values property in any container is itself read-only, meaning that you can’t assign some other arbitrary array to it, you can manipulate the contents of the array however you like.

We can see this in the Application data sample, which is a good reference for many of the core app data operations. Scenario 2, for example (js/settings.js), shows the simply use of the localSettings.values array:


var localSettings = Windows.Storage.ApplicationData.current.localSettings;
var settingName = "exampleSetting";
var settingValue = "Hello World";

function settingsWriteSetting() {
    localSettings.values[settingName] = settingValue;
}

function settingsDeleteSetting() {
    localSettings.values.remove(settingName);
}

Many settings, like that shown above, are just simple key-value pairs, but other settings will be objects with multiple properties. This presents a particular challenge: although you can certainly write and read the individual properties of that object within the values array, what happens if a failure occurs with one of them? That would cause your state to become corrupt.

To guard against this, the app data APIs provide for composite settings, which are groups of individual properties that are guaranteed to be managed as a single unit. (Again, each composite has a 64K limit.) It’s like the perfect group consciousness: either we all succeed or we all fail, with nothing in between! That is, if there’s an error reading or writing any part of the composite, the whole composite fails; with roaming, either the whole composite roams or none of it roams.

A composite object is created using Windows.Storage.ApplicationDataCompositeValue, as shown in Scenario 4 of the Application data sample (js/compositeSettings.js):

var roamingSettings = Windows.Storage.ApplicationData.current.roamingSettings;
var settingName = "exampleCompositeSetting";
var settingName1 = "one";
var settingName2 = "hello";

function compositeSettingsWriteCompositeSetting() {
    var composite = new Windows.Storage.ApplicationDataCompositeValue();
    composite[settingName1] = 1; // example value
    composite[settingName2] = "world"; // example value
    roamingSettings.values[settingName] = composite;
    }

function compositeSettingsDeleteCompositeSetting() {
    roamingSettings.values.remove(settingName);
}

function compositeSettingsDisplayOutput() {
    var composite = roamingSettings.values[settingName];
    // ...
}

The ApplicationDataCompositeValue object has, as you can see in the documentation, some additional methods and events to help you manage it such as clear, insert, and mapchanged.

Composites are, in many ways, like their own kind of settings container, just that they cannot contain additional containers. It’s important to not confuse the two. Child containers within settings are used only to create a hierarchy (refer to Scenario 3 in the sample). Composites, on the other hand, specifically exist to create more complex groups of settings that act like a single unit, a behavior that is not guaranteed for settings containers themselves.

As noted earlier, these settings are all written to the settings.dat file in your app data Settings folder. It’s also good to know that changes you make to settings containers are automatically saved, though there is some built-in batching to prevent excessive disk activity when you change a number of values all in a row. In any case, you really don’t need to worry about when you save settings; the system will manage those details.

Versioning App State

From Windows’ point of view, local, temp, and roaming state are all parts of the same whole and all share the same version. That version number is set with Windows.Storage.ApplicationData.-setVersionAsync, the value of which you can retrieve through Windows.Storage.Application-Data.version (a read-only property). If you like, you can maintain your own versioning system within particular files or settings. I would recommend, however, that you avoid doing this with roaming data because it’s hard to predict how Windows will manage synchronizing slightly different structures. Even with local state, trying to play complex versioning games is, well, rather complex, and probably best avoided altogether.

The version of your app data is also a different matter than the version of your app; in fact, there is really no inherent relationship between the two. While the app data version is set with setVersion-Async, the app version is managed through the Packaging section of the app manifest. You can have versions 1.0.0.0 through 4.3.9.3 of the app use version 1.0.0.0 of app data, or maybe version 1.2.1.9 of the app shifts to version 1.0.1.0 of the app data, and version 2.1.1.3 moves to 1.2.0.0 of the app data. It doesn’t really matter, so long as you keep it all straight and can migrate old versions of the app data to new versions!

Migration happens as part of the setVersionAsync call, whose second parameter is a function to handle the conversion. That function receives a SetVersionRequest object that contains currentVersion and desiredVersion properties, thereby instructing your function as to what kind of conversion is actually needed. In response, you should go through all your app data and migrate the individual settings and files accordingly. Once you return from the conversion handler, Windows will assume the migration is complete. Of course, because the process will often involve asynchronous file I/O operations, you can use a deferral mechanism like that we’ve seen with activation. Call the SetVersionRequest.getDeferral method to obtain the deferral object (a SetVersionDeferral), and call its complete method when all your async operations are done. Examples of this can be found in Scenario 9 of the Application data sample.

It is also possible to migrate app data when a new app update has been installed. For this you use a background task for the servicingComplete trigger. See Chapter 13, “Tiles, Notifications, the Lock Screen, and Background Tasks,” specifically the “Background Tasks and Lock Screen Apps” section toward the end.

Storage Folders and Storage Files

As it is often highly convenient to save app data directly in file, it’s high time we start looking more closely at the File I/O APIs for Windows Store apps.

First, however, other APIs like URL.createObjectURL—working with what are known as blobs—make it possible to do many things in an app without having descend to the level of file I/O at all! We’ve already seen how to use this to set the src of an img element, and the same works for other elements like audio, video, and iframe. The file I/O operations involved with such elements is encapsulated within createObjectURL. There are other ways to use a blob as well, such as converting a canvas element with canvas.msToBlob into something you can assign to an img element, and obtaining a binary blob from WinJS.xhr, saving it to a file, and then sourcing an img from that. We’ll see some more of this in Chapter 10, “Media,” and you can refer to the Using a blob to save and load content sample for more.

For working directly with files, now, let’s get a bearing on what we have at our disposal, with concrete examples supplied by the File access sample.

The core WinRT APIs for files live within the Windows.Storage namespace. The key players are the StorageFolder and StorageFile classes. These are sometimes referred to generically as “storage items” because they are both derived from IStorageItem and share properties like name, path, dateCreated, and attributes properties along with the methods deleteAsync and renameAsync.

File I/O in WinRT almost always starts by obtaining a StorageFolder object through one of the methods below. In a few cases you can also get to a StorageFile directly:

Windows.ApplicationModel.Package.current.installedLocation gets a StorageFolder through which you can load data from files in your package (all files therein are read-only).

Windows.Storage.ApplicationData.current.localFolder, roamingFolder, or temporaryFolder provides StorageFolder objects for your app data locations (read-write).

• An app can allow the user to select a folder or file directly using the file pickers invoked through Windows.Storage.Pickers.FolderPicker plus FileOpenPicker and FileSavePicker. This is the preferred way for apps that don’t need to enumerate contents of a library (see next bullet). This is also the only means through which app can access safe (nonsystem) areas of the file system without additional declarations in the manifest.

Windows.Storage.KnownFolders provides StorageFolder objects for the Pictures, Music, Videos, and Documents libraries, as well as Removable Storage. Given the appropriate capabilities in your manifest, you can work with the contents of these folders. (Attempting to obtain a folder without the correct capability with throw an Access Denied exception.)

• The Windows.Storage.DownloadsFolder object provides a createFolderAsync method through which you can obtain a StorageFolder in that location. It also provides a createFileAsync method to create a StorageFile directly. You would use this API if your app manages downloaded files directly. Note that DownloadsFolder itself provides only these two methods; it is not a StorageFolder in its own right.

• The static method Windows.Storage.StorageFolder.getFolderFromPathAsync returns a StorageFolder for a given pathname if and only if your app already has permissions to access it; otherwise, you’ll get an Access Denied exception. A similar static method exists for files called Windows.Storage.StorageFile.getFileFromPathAsync, with the same restrictions; Windows.Storage.StorageFile.getFileFromApplicationUriAsync opens files with ms-appx:// (package) and ms-appdata:/// URIs. Other schemas are not supported.

• Once a folder or file object is obtained, it can be stored in the Windows.Storage.-AccessCache that allows an app to retrieve it sometime in the future with the same programmatic permissions. This is primarily needed for folders or files selected through the pickers because permission to access the storage item is granted only for the lifetime of that in-memory object. You should always use this API, as demonstrated in Scenario 6 of the File access sample, where you’d normally think to save a file path. Again, StorageFolder.getFolder-FromPathAsync and StorageFile.getFileFromPathAsync will throw Access Denied exceptions if they refer to any locations where you don’t already have permissions. Pathnames also will not work for files provided by another app through the file picker, because the StorageFile object might not, in fact, refer to anything that actually exists on the file system.

Once you have a StorageFolder in hand, you can do the kinds of operations you’d expect: obtain folder properties (including a thumbnail), create and/or open files and folders, and enumerate the folder’s contents. With the latter, the API provides for obtaining a list folder contents, of course (see the getItemsAsync method), but what you want more often is a partial list of those contents according to certain criteria, along with thumbnails and other indexed file metadata (music album and track info, picture titles and tags, etc.) that you can use to group and organize the files. This is the purpose of file, folder, and item (file + folder) queries, which you manage through the methods createFileQuery-[WithOptions], createFolderQuery[WithOptions], and createItemQuery[WithOptions]. We already saw a little of this with the FlipView app we built using the Pictures Library in Chapter 5, “Collection and Collection Controls” and we’ll return to the subject in the context of user data, the primary scenario for queries, at the end of this chapter.41

Tip There are some file extensions that are reserved by the system and won’t be enumerated, such as .lnk, .url, and others; a complete list is found on the How to handle file activation topic. Also note that the ability to access UNC pathnames requires the Private Networks (Client & Server) and Enterprise Authentication capabilities in the manifest along with declarations of the file types you wish to access.

With any given StorageFolder, especially for your app data locations, you can create whatever folder structures you like through its createFolderAsync/getFolderAsync methods, which give you more StorageFolder objects. Within any of those folders you then use the createFileAsync/getFileAsync methods to access individual files, each of which you again see as a StorageFile object.

Each StorageFile provides relevant properties like name, path, dateCreated, fileType, contentType, and attributes, of course, along with methods like getThumbnailAsync, copyAsync, deleteAsync, moveAsync, moveAndReplaceAsync, and renameAsync for file management purposes. A file can be opened in a number of ways depending on the kind of access you need, using these methods:

openAsync and openReadAsync provide random-access byte-reader/writer streams. The streams are IRandomAccessStream and IRandomAccessStreamWithContentType objects, respectively, both in the Windows.Storage.Streams namespace. The first of these works with a pure binary stream; the second works with data+type information, as would be needed with an http response that prepends a content type to a data stream.

openSequentialReadAsync provides a read-only Windows.Storage.Streams.-IInputStream object through which you can read file contents in blocks of bytes but cannot skip back to previous locations. You should always use this method when you simply need to consume the stream as it has better performance than a random access stream (the source can optimize for sequential reads).

openTransactedWriteAsync provides a Windows.Storage.StorageStreamTransaction that’s basically a helper object around an IRandomAccessStream with commitAsync and close methods to handle the transactioning. This is necessary when saving complex data to make sure that the whole write operation happens atomically and won’t result in corrupted files if interrupted. Scenario 4 of the File access sample shows this.

The StorageFile class also provides two static methods, createStreamedFileAsync and createStreamedFileFromUriAsync. These provide a StorageFile that you typically pass to other apps through contracts as we’ll see more of in Chapter 12. The utility of these methods is that the underlying file isn’t accessed at all until data is first requested from it, if such a request ever happens at all.

Pulling all this together now, here’s a little piece of code using the raw API we’ve seen thus far to create and open a “data.tmp” file in our temporary AppData folder, and write a given string to it. This bit of code is in the RawFileWrite example for this chapter. Let me be clear that what’s shown here utilizes the lowest-level API in WinRT for this purpose and isn’t what you typically use, as we’ll see in the next section. It’s instructive nonetheless as there are times you need to use something similar:


var fileContents = "Congratulations, you're written data to a temp file!";
writeTempFileRaw("data.tmp", fileContents);


function writeTempFileRaw(filename, contents) {
    var tempFolder = Windows.Storage.ApplicationData.current.temporaryFolder;
    var outputStream;

    //Egads!
    tempFolder.createFileAsync(filename,
        Windows.Storage.CreationCollisionOption.replaceExisting)
    .then(function (file) {
        return file.openAsync(Windows.Storage.FileAccessMode.readWrite);
    }).then(function (stream) {
        outputStream = stream.getOutputStreamAt(0);
        var writer = new Windows.Storage.Streams.DataWriter(outputStream);
        writer.writeString(contents);
        return writer.storeAsync();
    }).done();
}

Good thing we learned about chained async operations a while back! First we create or open the specified file in our app data’s temporaryFolder (createFileAsync), and then we obtain an output stream for that file (openAsync and getOutputStreamAt). We then create a DataWriter around that stream, write our contents into it (writeString), and make sure it’s stored in the file (storeAsync).

But, you’re saying, “You’ve got to be kidding me! Four chained async operations just to write a simple string to a file! Who designed this API?” Indeed, when we started building the very first Store apps within Microsoft, this is all we had, and we asked these questions ourselves! After all, doing some hopefully simple file I/O is typically the first thing you add to a Hello World app, and this was anything but simple. To make matters worse, at that time we didn’t yet have promises for async operations in JavaScript, so we had to write the whole thing with raw nested operations. Such were the days.

Fortunately, simpler APIs were already available and more came along shortly thereafter. These are the APIs you’ll typically use when working with files as we’ll see in the next section. It is nevertheless important to understand the structure of the low-level code above because the Window.Storage.-Streams.DataWriter class shown in that code, along with its DataReader sibling, are very important mechanisms for working with a variety of different I/O streams and are essential for data encoding processes. Having control over the fine details also supports scenarios such as having different components in your app that are all contributing to the file structure. So it’s good to take a look at their reference documentation along with the Reading and writing data sample just so that you’re familiar with the capabilities.

Developers who have worked with file I/O APIs in the past sometimes ask why the StorageFile object doesn’t have some kind of close method on it. The reason for this is because the StorageFile itself represents a file entity, not a data stream through which you can access its contents. It’s when you call methods like StorageFile.openAsync to obtain a stream that the file is actually open, and the file is only closed when you close the stream through its particular close method.

You don’t see a call to that method in the code above, however, because the DataReader and DataWriter classes both take care of that detail for you when they are discarded. However, if you separate a stream from these objects through their detachStream methods, you’re responsible for calling the stream’s close method.

When developing apps that write to files, if you see errors indicating that the file is still open, check whether you’ve properly closed the streams involved.

The FileIO, PathIO, and WinJS helper classes (plus FileReader)

Simplicity is a good thing where File I/O is concerned, and the designers of WinRT made sure that the most common scenarios didn’t require a long chain of async operations like we saw in the previous section. The Windows.Storage.FileIO and PathIO classes provide such a streamlined interface, with the only difference between the two being that the FileIO methods take a StorageFile parameter whereas the PathIO methods take a filename string. Otherwise they offer the same methods called [read | write]BufferAsync (these work with byte arrays), [append | read | write]LinesAsync (these work with arrays of strings), and [append | read | write]TextAsync (these work with singular strings). In the latter case the WinJS.IOHelper class provides an even simpler interface through its readText and writeText methods.

Let’s see how those work, starting with a few examples from the File access sample. Scenario 2 shows writing a text string from a control to a file (this code is simplified from the sample for clarity):

var userContent = textArea.innerText;

//sampleFile created on startup from Windows.Storage.KnownFolders.documentsLibrary.getFileAsync
Windows.Storage.FileIO.writeTextAsync(sampleFile, userContent).done(function () {
    outputDiv.innerHTML = "The following text was written to '" + sampleFile.name
        + "':<br /><br />" + userContent;
    });

To compare to the example in the previous section, we can replace all the business with streams and DataWriters with one line of code:

tempFolder.createFileAsync(filename, Windows.Storage.CreationCollisionOption.replaceExisting)
.then(function (file) {
    Windows.Storage.FileIO.writeTextAsync(file, contents).done();
})

To make it even simpler, the WinJS.Application.temp object (WinJS.Application.IOHelper) reduces even this down to a single line (which is an async call and returns a promise):

WinJS.Application.temp.writeText(file, contents);

Reading text through the async readText method is equally simple, and WinJS provides the same interface for the local and roaming folders along with two other methods, exists and remove.42 That said, these WinJS helpers are available only for your AppData folders and not for the file system more broadly; for that you should be using the FileIO and PathIO classes.

You also have the HTML5 FileReader class available for use in Windows Store apps, which is part of the W3C File API specification. As its name implies, it’s suited only for reading files and cannot write them, but one of its strengths is that it can work both with files and blobs. Some examples of this are found in the Using a blob to save and load content sample.

Encryption and Compression

WinRT provides two capabilities that might be very helpful to your state management: encryption and compression.

Encryption is provided through the Windows.Security.Cryptography and Windows.-Security.Cryptography.Core API. The former contains methods for basic encoding and decoding (base64, hex, and text formats); the latter handles actual encryption according to various algorithms. As demonstrated in the Secret saver encryption sample, you typically encode data in some manner with the Windows.Security.Cryptography.CryptographicBuffer.convertStringToBinary method and then create or obtain an algorithm and pass that with the data buffer to Windows.-Security.Cryptography.Core.CryptographicEngine.encrypt. Methods like decrypt and convertBinaryToString perform the reverse.

Compression is a little simpler in that its only purpose is to provide a built-in API through which you can make your data smaller (say, to decrease the size of your roaming data). The API for this in Windows.Storage.Compression is composed of Compressor and Decompressor classes, both of which are demonstrated in the Compression sample. Although this API can employ different compression algorithms, including one called MSZIP, it does not provide a means to manage .ZIP files and the contents therein. For this purpose you’ll need to employ either a third-party JavaScript library or you can write a WinRT component in C# or Visual Basic that can use the System.IO.Compression APIs (see Chapter 16, “WinRT Components.”)

Using App Data APIs for State Management

Now that we’ve seen the nature of the APIs, let’s see how they’re used for different kinds of app data and any special considerations that come into play.

Session State

As described before, session state is whatever an app saves when being suspended so that it can restore itself to that state if it’s terminated by the system and later restarted. Being terminated by the system is again the only time this happens, so what you include in session state should always be scoped to giving the user the illusion that the app was running the whole time. In some cases, as described in Chapter 3, you might not in fact restore this state, especially if it’s been a long time since the app was suspended and it’s unlikely the user would really remember where they left off. That’s a decision you need to make for your own app and the experience you want to provide for your customers.

Session state should be saved within the appdata localFolder or the localSettings object. It should not be saved in a temp area since the user could run the disk cleanup tool while your app is suspended or terminated in which case session state would be deleted (see next section).

The WinJS sessionState object internally creates a file called _sessionState.json within the localFolder. The file is just JSON text, so you can examine it any time. You can and should write session state variables to the sessionState object whenever they change, using sessionState essentially as a namespace for those session variables. This way those values get saved and reloaded automatically without needing to manage variables somewhere else.

If you need to store additional values within sessionState before its written, do that in your handler for WinJS.Application.oncheckpoint. A good example of such data is the navigation stack for your page controls, which is available in WinJS.Navigation.history; you could also copy this data to sessionState within the PageControlNavigator.navigated method (in navigator.js as provided by the project templates). In any case, WinJS has its own checkpoint handler that is always called last (after your handler) to make sure that any changes you make to sessionState in response to that event are saved.

If you don’t use the WinJS sessionState object and just use the WinRT appdata APIs directly, you can write your session state whenever you like (including within checkpoint), and you’ll need to restore it directly within your activated event for previousExecutionState == terminated.

It’s also a good practice to build some resilience into your handling of session state: if what gets loaded doesn’t seem consistent or has some other problem, revert to default session values. Remember too that you can use the localSettings container with composite settings to guarantee that groups of values will be stored and retrieved as a unit. You might also find it helpful during development to give yourself a simple command to clear your app state in case things get really fouled up, but just uninstalling your app will clear all that out as well. At the same time, it’s not necessary to provide your users with a command to clear session state: if your app fails to launch after being terminated, the previousExecutionState flag will be notRunning the next time the user tries, in which case you won’t attempt to restore the state.

Similarly, it’s not necessary to include a version number in session state. If the user installs an update during the time your app has been suspended and terminated, and the appdata version changes, the previousExecutionState value will be reset. If for some reason you don’t actually change the appdata version—for instance, if your update is only very minor—then your session state can carry forward. But in this case it’s essentially the same app, so versioning the state isn’t an issue.

If you prefer, you can use HTML5 localStorage object for both session and other local app data; its contents get persisted to the app data localFolder. The contents of localStorage are not loaded until first accessed and are limited to 10MB per app; the WinRT and WinJS APIs, on the other hand, are limited only by the capacity of the file system.

As for the HTML5 sessionStorage object, it’s not really needed when you’re using page controls and maintaining your script context between app pages—your in-memory variables already do the job. However, if you’re actually changing page contexts by using <a> links or setting document.location, sessionStorage can still be useful. You can also encode information into URIs as commonly done with web apps.

Both sessionStorage and localStorage are also useful within iframe pages running in the web context, since the WinRT APIs are not available. At the same time, you can load WinJS into a web context page (this is supported) and the WinJS.Application.local, roaming, and temp objects still work using in-memory buffers instead of the file system.

Local and Temporary State

Unlike session state that is restored only in particular circumstances, local app state is composed of those settings and other values that are always applied when an app is launched. Anything that the user can set directly falls into this category, unless it’s also part of the roaming experience in which case it is still loaded on app startup. Any other cached data, saved searches, recently used items, display units, preferred media formats, and device-specific configurations also fall into this bucket. In short, if it’s not pure session state and not part of your app’s roaming experience, it’s local or temporary state. (Remember again that credentials should be stored in the Credential Locker instead of your appdata.)

All the same APIs we’ve seen work for this form of state, including all the WinRT APIs, the WinJS.Application.local and temp objects, and HTML localStorage. You can also use the HTML5 IndexedDB APIs, SQLite, and the HTML App Cache—these are just other forms of local app data.

It’s very important to version-stamp your local and temp app data because it will always be preserved across an app update (unless temp state has been cleaned up in the meantime). With any app update, be prepared to load old versions of your state and make the necessary updates, or simply decide that a version is too old and purge it (Windows.Storage.ApplicationData.current.clearAsync) before setting up new defaults. As mentioned before, it’s also possible to migrate state from a background task. (See Chapter 13.)

Generally speaking, local and temp app data are the same—they have the same APIs and are stored in parallel folders. Temp, however, doesn’t support settings and settings containers. The other difference is that the contents of your temp folder (along with the HTML5 app cache) are subject to the Windows Disk Cleanup tool. This means that your temp data could disappear at any time when the user wants to free up some disk space. You could also employ a background task with a maintenance trigger for doing cleanup on your own (again see Chapter 13, in the section “Tasks for Maintenance Triggers.”)

For these reasons, temp should be used for storage that optimizes your apps performance but not for anything that’s critical to its operation. For example, if you have a JSON file in your package that you parse or decompress on first startup such that the app runs more quickly afterwards, and you don’t make any changes to that data from the app, you might elect to store that in temp. The same is true for graphical resources that you might have fine-tuned for the specific device you’re running on; you can always repeat that process from the original resources, so it’s another good candidate for temp data. Similarly, if you’ve acquired data from an online service as an optimization (that is, so that you can just update the local copy incrementally), you can always reacquire it. This is especially helpful for providing an offline experience for your app, though in some cases you might want to let the user choose to save it in local instead of temp (an option that would appear in Settings along with the ability to clear the cache).

Store apps can employ the HTML 5 app cache as part of an offline/caching strategy. It is most useful in iframe web context elements where it can be used for any kind of content. For example, an app that reads online books can show such content in an iframe, and if those pages include app cache tags, they’ll be saved and available offline. In the local context, the app cache works for nonexecutable resources like images, audio, and video, but not for HTML or JavaScript.

IndexedDB and Other Database Options

Many forms of local app data are well suited to being managed in a database. In Windows Store apps, the IndexedDB API is available through the window.indexedDB and worker.indexedDB objects. For complete details on using this feature, I’ll refer you to the W3C specifications, the Indexed Database API reference for Store apps, and the IndexedDB sample.

Although an IndexedDB database is stored within your app’s local app data, be aware that there are some limitations because there isn’t a means through which the app or the system can shrink a database file and reclaim unused space:

• IndexedDB has a 250MB limit per app and an overall system limit of 375MB on drives smaller than 32GB, or 4% (to a maximum 20GB) for drives over 32GB. So it could be true that your app might not have much room to work with anyway, in which case you need to make sure you have a fallback mechanism. (When the limit is exceeded the APIs will throw a Quota Exceeded exception.)

• IndexedDB on Windows 8 has no complex key paths—that is, it does not presently support multiple values for a key or index (multientry).

• By default, access to IndexedDB is given only to HTML pages that are part of the app package and those declared as content URIs. (See the “Local and Web Contexts within the App Host” section at the beginning of Chapter 3.) Random web pages you might host in an iframe will not be given access, primarily to preserve space within the 250MB limit for those pages you really care about in your app. However, you can grant access to arbitrary pages by including the following tag in your home page and not setting the iframe src attribute until the DOMContentLoaded or activated event has fired:

    <meta name="ms-enable-external-database-usage" content="true"/>

Beyond IndexedDB there are a few other database options for Store apps. For a local relational database, try SQLite. This is an API that’s suited well for apps written in a language like C#, as described in Tim Heuer’s blog on the subject, but fortunately, there is a version called SQL.js, which is SQLite compiled to JavaScript via Emscripten. Very cool! There might also be other JavaScript solutions available in the community.

If the storage limits for IndexedDB are a concern, you might use the Win32 “Jet” or Extensible Storage Engine (ESE) APIs (on which the IndexedDB implementation is built). For this you’ll need to write a WinRT Component wrapper in C# or C++ (the general process for which is in Chapter 16, “WinRT Components”), since JavaScript cannot get to those APIs directly.

The same is true for other third-party database APIs. So long as that engine uses only the Win32 APIs allowable for Store apps (listed on the Win32 and COM for Windows Store apps page), they’ll work just fine.

It’s also worth noting that the OData Library for JavaScript also works great for Store apps to access online SQL Servers, because the OData protocol itself just works via REST.

Finally, another option for searchable file-backed data is to use the system index by creating a folder named “indexed” in your local AppData folder. The contents of the files in this folder will be indexed by the system indexer and can be queried using Advanced Query Syntax (AQS) with the APIs explained later in “Rich Enumeration with File Queries.” You can also do property-based searched for Windows properties, making this approach a simple alternative to database solutions.

Roaming State

The automatic roaming of app state between a user’s devices is one of the most interesting and enabling features of Windows 8. There are few areas where a small piece of technology like this has so greatly reduced the burden on app developers!

It works very simply. First, your app data roamingFolder and your roamingSettings container behave exactly like their local counterparts. So long as their combined size is less than Windows.Storage.-ApplicationData.current.roamingStorageQuota, Windows will copy that data to other devices where the same user is logged in has the same app installed; in fact, when an app is installed, Windows attempts to copy roaming data so that it’s there when the app is first launched.

If the app is running simultaneously on multiple devices, the last writer of any particular file or setting always wins. When data has been roamed the other apps will receive the Windows.Storage.-ApplicationData.ondatachanged event. So your app will always read the appropriate roaming state on startup and refresh that state as needed within datachanged. You should always employ this strategy too in case Windows cannot bring down roaming state for a newly installed app right away (such as when the user installed the app and lost connectivity). As soon as the roaming state appears, you’ll receive the datachanged event. Scenario 5 of the Application data sample provides a basic demonstration of this.

Deciding what your roaming experience really looks like is really a design question more than a development question. It’s a matter of taking all app settings that are not specific to the device hardware (such as settings that are related to screen size, video capabilities, or the presence of particular peripherals or sensors), and thinking through whether it makes sense for each setting to be roamed. A user’s favorites, for example, are appropriate to roam if they refer to data that isn’t local to the device. That is, favorite URIs or locations on a cloud storage service like SkyDrive, FaceBook, or Flickr are appropriate to roam; favorites and recently used files in a user’s local libraries are not. The viewing position within a cloud-based video, like a streaming movie, would be appropriate to roam, as would be the last reading position in a magazine or book. But again, if that content is local, then maybe not. Account configurations like email settings are often good candidates, so the user doesn’t have to configure the app again on other devices.

At the same time, you might not be able to predict whether the user will really want to roam certain settings. In this case, the right choice is to give the user a choice! That is, include options in your Settings UI to allow the user to customize the roaming experience to their liking, especially as a user might have devices for both home and work where they want the same app to behave differently. For instance, with an RSS Reader the user might not want notifications on their work machine whenever new articles arrive, but would want real-time updates at home. The set of feeds itself, on the other hand, would probably always be roamed, but then again the user might want to keep separate lists.

To minimize the size of your roaming state and stay below the quota, you might employ the Windows.Storage.Compression API for file-based data. For this same reason, never use roaming state for user data. Instead, use an online service like SkyDrive to store user data in the cloud, and then roam URIs to those files as part of the roaming experience. More details on using SkyDrive through its REST API can be found on the SkyDrive reference, on the Skydrive core reference (which includes a list of supported file types), and in the PhotoSky sample. A backgrounder on this and other Windows Live services can also be found on the Building Windows 8 blog post entitled Extending "Windows 8" apps to the cloud with SkyDrive.

By now you probably have a number of other questions forming in your mind about how roaming actually works: “How often is data synchronized?” “How do I manage different versions?” “What else should I know?” These are good questions, and fortunately there are good answers!

• Assuming there’s network connectivity, an app’s roaming state is roamed within 30 minutes on an active machine. It’s also roamed immediately when the user logs on or locks the machine. Locking the machine is always the best way to force a sync to the cloud. Note that if the cloud service is only aware of the user (that is, a Microsoft account) having only one device, synchronization with the cloud service happens only about once per day. When the service is aware that the user has multiple machines, it begins synchronizing within the 30-minute period; if the app is uninstalled on all but one machine, synchronization reverts to the longer period.

• When saving roaming state, you can write values whenever you like, such as when those settings are changed. You don’t need to worry about writing settings as a group because Windows has a built-in debounce period to combine changes together and reduce overall network traffic.

• If you have a group of settings that really must be roamed together, manage these as a composite setting in your roamingSettings container.

• With files you create within the roamingFolder, these will not be roamed so long as you have the file open for writing (that is, as long as you have an open stream). It’s a good idea to make sure that all streams are closed when the app is suspended.

• Windows allows each app to have up to 8K worth of “high priority” settings that will be roamed within one minute, thereby allowing apps on multiple devices to stay much more closely in sync. To use this, create a single or composite setting in the root of your roamingSettings with the name HighPriority—that is, roamingSettings.values["HighPriority"] (a container with this name will roam normally). So long as you keep the size of this setting below 8K, it will be roamed within a minute of being changed; if you exceed that size, it will be roamed with normal priority. See Scenario 6 of the Application data sample for a demonstration.

• On a trusted PC, systemwide user settings like the Start page configuration are automatically roamed independent of app. This also includes encrypted credentials saved by apps in the credential locker; apps should never attempt to roam passwords. Apps that create secondary tiles (as we’ll see in Chapter 13) can indicate whether such tiles should be copied to a new device when the app is installed.

• When there are multiple app data versions in use by the same app (with multiple app versions, of course), Windows will manage each version of the app data separately, meaning that newer app data won’t be roamed to devices with apps that use older app data versions. In light of this, it’s a good idea to not be too aggressive in versioning your app data since it will break the roaming connection between apps.

• The cloud service will retain multiple versions of roaming app data so long as there are multiple versions in use by the same Microsoft account. Only when all instances of the app have been updated will older versions of the roaming state be eligible for deletion.

• When an updated app encounters an older version of roaming state, it should load it according to the old version but save it as the new version and call setVersionAsync.

• Avoid using secondary versioning schemes within roaming state such that you introduce structural differences without changing the appdata version through setVersionAsync. Because the cloud service is managing the roaming state by this version number, and because the last writer always wins, some version of an app that expects to see some extra bit of data, and in fact saved it there, might find that it’s been removed because a slightly older version of the app didn’t write it.

• Even if all apps are uninstalled from a user’s devices, the cloud service retains roaming data for “a reasonable time” (maybe 30 days) so that if a user reinstalls the app within that time period they’ll find that their settings are still intact. To avoid this retention and explicitly clear roaming state from the cloud, use the clearAsync method.

Settings Pane and UI

We’ve now seen all the different APIs that an app can use to manage its state where storage is concerned. This is all you need for settings and other app data that are managed internally within the app. The question now is how to manage user-configurable settings, and for that we turn to the Settings charm.

When the user invokes the Settings charm (which can also be done directly with the Win+i key), Windows displays the Settings pane, a piece of UI that is populated with various settings commands as well as system functions along the bottom. Apps can add their own commands but are not obligated to do so. Windows guarantees that something always shows up for the app in this pane: it automatically displays the app name and publisher, a Rate and Review command that takes you to the Windows Store page for the app, an Update command if an update is available from the Store, and a Permissions command if the app has declared any capabilities in its manifest. (Note that Rate and Review won’t appear for apps you run from Visual Studio since they weren’t acquired from the Store.)

The Settings charm is always available no matter where you are in the app, so you don’t need to think about having such a command on your app bar, nor do you ever need a settings command on your app canvas. That said, you can invoke the Settings charm programmatically, such as when you detect that a certain capability is turned off and you prompt the user about that condition. You might ask something like “Do you want to turn on geolocation for this app?” and if the user says Yes, you can invoke the Settings charm. This is done through the settings pane object returned from Windows.UI.ApplicationSettings.SettingPane.getForCurrentView, whose show method display the UI (or throws a kindly exception if the app is in snapped view or doesn’t have the focus, so don’t invoke it under those conditions!). The edge property of the settings pane object also tells you if it’s on the left or right side of the screen, depending on the left-to-right or right-to-left orientation of the system as a whole (a regional variance).

And with that we’ve covered all the methods and properties of this object! Yet the most interesting part is how we add our own commands to the settings pane. But let’s first look at the guidelines for using Settings.

Design Guidelines for Settings

Beyond the commands that Windows automatically adds to the settings pane, the app can provide up to eight others, typically around four; anything more than eight will throw an exception. Because settings are global to an app, the commands you add are always the same: they are not sensitive to context. To say it another way, the only commands that should appear on the settings pane are those that are global to the app; commands that apply only to certain pages or contexts within a page should appear on the app bar or on the app canvas. Some examples of commands on the top-level settings pane are shown in Figure 8-2.

images

FIGURE 8-2 Examples of commands on the top-level settings pane. Notice that the lower section of the pane always has system settings and the app name and publisher always appear at the top. Permissions and Rate and Review are added automatically.

Each app-supplied command can do one of two things. First, a command can simply be a hyperlink to a web page. Some apps use links for their Help, Privacy Statement, Terms of Use, License Agreements, and so on, which will open the linked pages in a browser. The other option is to have the command invoke a secondary flyout panel with more specific settings controls or simply an iframe to display web-based content. You can provide Help, Terms of Use, and other textual content in both these ways rather than switch to the browser.

Note As stated in the Windows 8 app certification requirements, section 4.1, apps that collect personal information in any way must have a privacy policy or statement. This must be included on the app’s product description page in the Store as a minimum. Though not required, it is suggested that you also include a command for this in your Settings pane.

Secondary flyouts are created with the WinJS.UI.SettingsFlyout control; some examples are shown in Figure 8-3. Notice that the secondary settings panes come in two sizes: narrow (346px) and wide (646px). The design guidelines suggest that all secondary panes for an app are the same size—that is, don’t make some narrow and some wide. You’ll only have a couple of these panes anyway, so that shouldn’t be a problem. Also note that the Permissions flyout, shown on the left of Figure 8-3, is provided by Windows automatically and is configured according to capabilities declared in your manifest. Some capabilities like geolocation are controlled in this pane; other capabilities like Internet and library access are simply listed because the user is not allowed to turn them on or off.

images

FIGURE 8-3 Examples of secondary settings panes in the Travel, Weather, News, and Music apps of Windows 8. The first three are the narrow size; the fourth is wide. Notice that each app-provided pane is appropriately branded and provides a back button to return to the main Settings pane. The Permissions pane is provided by the system and thus reflects the system theme; it cannot be customized.

A common group of settings are those that allow the user to configure their roaming experience—that is, a group of settings that determine what state is roamed (you see this on PC Settings > Sync Your Settings). It is also recommended that you include account/profile management commands within Settings, as well as login/logout functionality. As noted in Chapter 7, logins and license agreements that are necessary to run the app at all should be shown upon launch. For ongoing login-related functions, and to review license agreements and such, create the necessary commands and panes within Settings. Refer to Guidelines and checklist for login controls for more information on this subject. Guidelines for a Help command can also be found on Adding app help.

Behaviorally, settings panes are light-dismiss but also have a header with a back button to return to the primary settings pane with all the commands. Because of the light-dismiss behavior, changing a setting on a pane applies the setting immediately: there is no OK or Apply button or other such UI. If the user wants to revert a change, she should just restore the original setting.

For this reason it’s a good idea to use simple controls that are easy to switch back, rather than complex sets of controls that would be difficult to undo. The recommendation is to use toggle switches for on/off values (rather than check boxes), a button to apply an action (but without closing the settings UI), hyperlinks (to open the browser), text input boxes (which should be set to the appropriate type such as email address, password, etc.), radio buttons for groups of up to five mutually exclusive items, and a listbox (select) control for four to six text-only items.

In all your settings, think in terms of “less is more.” Avoid having all kinds of different settings, because if the user is never going to find them, you probably don’t need to surface them in the first place! Also, while a settings pane can scroll vertically, try to limit the overall size such that the user has to pan down only once or twice, if at all.

Some other things to avoid with Settings:

• Don’t use Settings for workflow-related commands. Those belong on the app bar or on the app canvas, as discussed in Chapter 7.

• Don’t use a top-level command in the Settings pane to perform an action other than linking to another app (like the browser). That is, top-level commands should never execute an action within the app.

• Don’t use settings commands to navigate within the app.

• Don’t use WinJS.UI.SettingsFlyout as a general-purpose control.

And on that note, let’s now look at the steps to use Settings and the SettingsFlyout properly!

Populating Commands

The first part of working with Settings is to provide your specific commands when the Settings charm is invoked. Unlike app bar commands, these should always be the same no matter the state of the app; if you have context-sensitive settings, place commands for those in the app bar.

There are two ways to implement this process in an app written in HTML and JavaScript: using WinRT directly, or using the helpers in WinJS. Let’s look at these in turn for a simple Help command.

To know when the charm is invoked through WinRT, obtain the settings pane object through Windows.UI.ApplicationSettings.SettingsPane.getForCurrentView and add a listener for its commandsrequested event (this is a WinRT event, so be sure to remove the listener if necessary):

// The n variable here is a convenient shorthand
var n = Windows.UI.ApplicationSettings;
var settingsPane = n.SettingsPane.getForCurrentView();
settingsPane.addEventListener("commandsrequested", onCommandsRequested);

Within your event handler, create Windows.UI.ApplicationSettings.SettingsCommand objects for each command, where each command has an id, a label, and an invoked function that’s called when the command is tapped or clicked. These can all be specified in the constructor as shown below:

function onCommandsRequested(e) {
    // n is still the shortcut variable to Windows.UI.ApplicationSettings
    var commandHelp = new n.SettingsCommand("help", "Help", helpCommandInvoked);
    e.request.applicationCommands.append(commandHelp);
}

The second line of code is where you then add these commands to the settings pane itself. You do this by appending them to the e.request.applicationCommands object. This object is a WinRT construct called a vector that manages a collection with commands like append and insertAt. In this case we have a vector of SettingsCommand objects, and as you can see above, it’s easy enough to append a command. You’d make such a call for each command, or you can pass an array of such commands to the replaceAll method instead of append. What then happens within the invoked handler for each command is the interesting part, and we’ll come back to that in the next section.

You can also prepopulate the applicationCommands vector outside of the commandsrequested event; this is perfectly fine because your settings commands should be constant for the app. The Quickstart: add app help topic shows an example of this, which I’ve modified here to show the use of replaceAll:

var n = Windows.UI.ApplicationSettings;
var settingsPane = n.SettingsPane.getForCurrentView();
var vector = settingsPane.applicationCommands;

//Ensure no settings commands are currently specified in the settings charm
vector.clear();

var commands = [ new settingsSample.SettingsCommand("Custom.Help", "Help", OnHelp),
                 new n.SettingsCommand("Custom.Parameters", "Parameters", OnParameters)];
vector.replaceAll(commands);

This way, you don’t actually need to register for or handle commandsrequested directly.

Now because most apps will likely use settings in some capacity, WinJS provides some shortcuts to this whole process. First, instead of listening for the WinRT event, simply assign a handler to WinJS.Application.onsettings (which is a wrapper for commandsrequested):

WinJS.Application.onsettings = function (e) {
    // ...
};

In your handler, create a JSON object describing your commands and store that object in e.detail.applicationcommands. Mind you, this is different from the WinRT object—just setting this property accomplishes nothing. What comes next is passing the now-modified event object to WinJS.UI.SettingsFlyout.populateSettings as follows (taken from Scenario 2 of the App settings sample):

WinJS.Application.onsettings = function (e) {
    e.detail.applicationcommands =
        { "help": { title: "Help", href: "/html/2-SettingsFlyout-Help.html" } };
    WinJS.UI.SettingsFlyout.populateSettings(e);
};

The populateSettings method traverses the e.details.applicationcommands object and calls the WinRT applicationCommands.append method for each item. This gives you a more compact method to accomplish what you’d do with WinRT, and it also simplifies the implementation of settings commands, as we’ll see next.

Note The WinJS helpers are specifically designed for invoking SettingsFlyout controls that are populated with the HTML file you indicate in the href property. That property must refer to in-package contents; it cannot be used to create settings commands that launch a URI (commonly used for Terms of Service and Privacy Statement commands). In such cases you must use the WinRT API directly alongside WinJS.UI.SettingsFlyout.populateSettings. Then again, it’s a simple matter to bring web content directly into a settings flyout with an iframe, which keeps the Settings experience within the app.

Implementing Commands: Links and Settings Flyouts

Technically speaking, within the invoked function for a settings command you can really do anything. Truly! Of course, as described in the design guidelines earlier, there are recommendations for how to use settings and how not to use them. For example, settings commands shouldn’t act like app bar commands that affect content, nor should they navigate within the app itself. Ideally, a settings command does one of two things: either launch a hyperlink (to open a browser) or display a secondary settings pane.

In the base WinRT model for settings, launching a hyperlink uses the Windows.System.-Launcher.launchUriAsync API as follows:


function helpCommandInvoked(e) {
    var uri = new Windows.Foundation.Uri("http://example.domain.com/help.html");
    Windows.System.Launcher.launchUriAsync(uri).done();
}

In the second case, secondary panes are implemented with the WinJS.UI.SettingsFlyout control. Again, technically speaking, you’re not required to use this control: you can display any UI you want within the invoked handler. The SettingsFlyout control, however, provides for the recommended narrow and wide sizes, supplies enter and exit animations, fires events like [before | after][show | hide]43 and other such features. And since you can place any HTML you want within the control, including other controls, and the flyout will automatically handle vertical scrolling, there’s really no reason not to use it.

As a WinJS control, you can declare a SettingsFlyout for each one of your commands in markup (making sure WinJS.UI.process/processAll is called, which handles any other controls in the flyout). For example, Scenario 2 of the App settings sample has the following flyout for help (omitting the text content and reformatting a bit), the result of which is shown in Figure 8-4:

<div data-win-control="WinJS.UI.SettingsFlyout" aria-label="Help settings flyout"
    data-win-options="{settingsCommandId:'help', width:'wide'}">
    <!-- Use either 'win-ui-light' or 'win-ui-dark' depending on the contrast between
         the header title and background color; background color reflects app's
         personality -->
    <div class="win-ui-dark win-header" style="background-color:#00b2f0">
        <button type="button" onclick="WinJS.UI.SettingsFlyout.show()"
            class="win-backbutton"></button>
        <div class="win-label">Help</div>
        <img src="../images/smallTile-sdk.png" style="position: absolute; right: 40px;"/>
    </div>
    <div class="win-content ">
        <div class="win-settings-section">
            <h3>Settings charm usage guidelines summary</h3>
            <!-- Other content omitted -->
            <li>For more in-depth usage guidance, refer to the
                <a href="http://msdn.microsoft.com/en-us/library/windows/apps/hh770544">
                App settings UX guide</a>.</li>
        </div>
    </div>
</div>

As always, there are options for this control as well as a few applicable win-* style classes. The only two options are settingsCommandId, for obvious purpose, and width, which can be 'narrow' or 'wide'. We see these both in the example above. The styles that apply here are win-settingsflyout, which styles the whole control (typically not used except for scoping other style rules), and win-ui-light and win-ui-dark, which apply a light or dark theme to the parts of the flyout. In this example, we use the dark theme for the header while the rest of the flyout uses the default light theme.

images

FIGURE 8-4 The Help settings flyout (truncated vertically) from Scenario 2 of the App settings sample. Notice the hyperlink on the lower right.

In any case, you can see that everything within the control is just markup for the flyout contents, nothing more, and you can wire up events to controls in the markup or in code. You’re free to use hyperlinks here, such as to launch the browser to open a fuller Help page. You can also use an iframe to directly host web content within a settings flyout, as demonstrated in Scenario 3 of the same sample.

So how do we get this flyout to show when a command is invoked on the top-level settings pane? The easy way is to let WinJS take care of the details using the information you provide to WinJS.UI.-SettingsFlyout.populateSettings. Here’s the example again from Scenario 2, as we saw in the previous section:

WinJS.Application.onsettings = function (e) {
    e.detail.applicationcommands =
        { "help": { title: "Help", href: "/html/2-SettingsFlyout-Help.html" } };
    WinJS.UI.SettingsFlyout.populateSettings(e);
};

In the JSON you assign to applicationCommands, each object identifies both a command and its associated flyout. The name of the object is the flyout id (“help”), its title property provides the command label for the top-level settings pane (“Help” in the above), and its href property identifies the HTML page where the flyout with that id is declared (“/html/2-SettingsFlyout-Help.html”).

With this information, WinJS can both populate the top-level settings pane and provide automatic invocation of the desired flyout (calling WinJS.UI.process all along the way) without you having to write any other code. This is why in most of the scenarios of the sample you don’t see any explicit calls to showSettings, just a call to populateSettings.

Programmatically Invoking Settings Flyouts

Let’s now see what’s going on under the covers. In addition to being a control that you use to define a specific flyout, WinJS.UI.SettingsFlyout has a couple of other static methods besides populateSettings: show and showSettings. The show method specifically brings out the top-level Windows settings pane—that is, Windows.UI.ApplicationSettings.SettingsPane. This is why you see the back button’s click event in the above markup wired directly to show, because the back button should return to that top-level UI.

Note While it’s possible to programmatically invoke your own settings panes, you cannot do so with system-provided commands like Permissions and Rate and Review. If you have a condition for which you need the user to change a permission, such as enabling geolocation, the recommendation is to display an error message that instructs the user to do so.

The showSettings method, on the other hand, shows a specific settings flyout that you define somewhere in your app. The signature of the method is showSettings(<id> [, <page>]) where <id> identifies the flyout you’re looking for and the optional <page> parameter identifies an HTML document to look in if a flyout with <id> isn’t found in the current document. That is, showSettings will always start by looking in the current document for a WinJS.UI.SettingsFlyout element that has a matching settingsCommandId property or a matching HTML id attribute. If such a flyout is found, that UI is shown.

If the markup in the previous section (with Figure 8-4) was contained in the same HTML page that’s currently loaded in the app, the following line of code will show that flyout:

WinJS.UI.SettingsFlyout.showSettings("help");

In this case you could also omit the href part of the JSON object passed to populateCommands, but only again if the flyout is contained within the current HTML document already.

The <page> parameter, for its part, allows you to separate your settings flyouts from the rest of your markup; its value is a relative URI within your app package. The App settings sample uses this to place the flyout for each scenario into a separate HTML file. You can also place all your flyouts in one HTML file, so long as they have unique ids. Either way, if you provide a <page>, showSettings will load that HTML into the current page using WinJS.UI.Pages.load (which calls WinJS.UI.processAll), scans that DOM tree for a matching flyout with the given <id>, and shows it. Failure to locate the flyout will cause an exception.

Scenario 5 of the sample shows this form of programmatic invocation. This is also a good example (see Figure 8-5) of a vertically scrolling flyout:

WinJS.UI.SettingsFlyout.showSettings("defaults", "/html/5-SettingsFlyout-Settings.html");

images

FIGURE 8-5 The settings flyout from Scenario 5 of the App settings sample, showing how a flyout supports vertical scrolling; note the scrollbar positions for the top portion (left) and the bottom portion (right).

A call to showSettings is thus exactly what you use within any particular command’s invoked handler and is what WinJS sets up within populateCommands. But it also means you can call showSettings from anywhere else in your code when you want to display a particular settings pane. For example, if you encounter an error condition in the app that could be rectified by changing an app setting, you can provide a button in the message dialog of notification flyout that calls showSettings to open that particular pane. And for what it’s worth, the hide method of that flyout will dismiss it; it doesn’t affect the top-level settings pane for which you must use Windows.UI.Application-Settings.SettingsPane.getForCurrentView.hide.

You might use showSettings and hide together, in fact, if you need to navigate to a third-level settings pane. That is, one of your own settings flyouts could contain a command that calls hide on the current flyout and then calls showSettings to invoke another. The back button of that subsidiary flyout (and it should always have a back button) would similarly call hide on the current flyout and showSettings to make its second-level parent reappear. That said, we don’t recommend making your settings so complex that third-level flyouts are necessary, but the capability is there if you have a particular scenario that demands it.

Knowing how showSettings tries to find a flyout is also helpful if you want to create a WinJS.-UI.SettingsFlyout programmatically. So long as such a control is in the DOM when you call showSettings with its id, WinJS will be able to find it and display it like any other. It would also work, though I haven’t tried this and it’s not in the sample, to use a kind of hybrid approach. Because showSettings loads the HTML page you specify as a page control with WinJS.UI.Pages.load, that page can also include its own script wherein you define a page control object with methods like processed and ready. Within those methods you could then make specific customizations to the settings flyout defined in the markup.

A common question along these lines is whether an app can receive events when the user changes settings within the Permissions pane. The answer is no, which means that you discover whether access is disallowed only by handling Access Denied exceptions when you try to use the capability. To be fair, though, you always have to handle denial of a capability gracefully because the user can always deny access the first time you use the API. When that happens, you again display a message about the disabled permission (as shown with the Here My Am! app from Chapter 7) and provide some UI to reattempt the operation. But the user still needs to invoke the Permissions settings manually. Refer also to the Guidelines for devices that access personal data for more details.

User Data: Libraries, File Pickers, and File Queries

Now that we’ve thoroughly explored app data and app settings, we’re ready to look at the other part of state: user data. User data, again, is all the good stuff an app might use or generate that isn’t specifically tied to the app. Multiple apps might be able to work with the same files, such as pictures and music, and user data always stays on a device regardless of what apps are present.

Our first concern with user data is where to put it and where to access it, which involves the various user data libraries, removable storage, and the file pickers. Using the access cache is also important to remember the fact that a user once granted access to a file or folder that we’re normally not allowed to touch programmatically. The good thing about all such files and folders is that working with them happens through the same StorageFolder and StorageFile classes we’ve already seen. The other main topic we’ll explore is that of file queries, a richer way to enumerate the contents of folders and libraries that lend very well to visual representations within controls like a ListView.

As we’ve seen, a Windows Store app, by default, has access only to its package and its AppData folders. This means that, by default, it doesn’t actually have any access to typical locations for user data! There are then two ways that such access is acquired:

• Declare a library capability in the manifest.

• Let the user choose a location through the File Picker.

We’ll look first at the File Picker, because in many cases it’s all you really need in an app! But there are other scenarios—such as gallery-style apps—where you need direct access, so there are five capabilities in the manifest for this purpose, as shown in Figure 8-6 (left side). Three of them—Music Library, Pictures Library, and Videos Library—grant full read-write access to the user’s Music, Pictures, and Videos folders. These appear on the app’s product page in the Windows Store and on the Permissions settings pane, but they are not subject to user consent at run time. Of course, if it’s not obvious why you’re declaring these capabilities, be sure to explain yourself on your product page. And as for Documents Library and Removable Storage, simply declaring the capability isn’t sufficient: you also need to declare specific file type associations to which you’re then limited. (The Documents Library capability is intended only for apps that need to open embedded content in another document.)

images

FIGURE 8-6 Capabilities related to user data in the manifest editor (left) and the file type association editor (right). Notice that the red X appears on Capabilities when additional declarations are needed in conjunction with this capability. The red X on Declarations indicates that the information is not yet complete.

A topic that’s relevant to user data, but one that we won’t cover in detail until Chapter 14 is the Windows.Networking.BackgroundTransfer API of WinRT. This API allows you to run downloads and uploads independently of app lifetime—that is, while the app is running, suspended, or not running at all. This API is provided because transfer of large files to and from online resources is a common need for apps but one that doesn’t really need the apps themselves to run in the background and consume power. Instead, apps set up transfer operations with the system that will continue if the app is shut down. When the app is relaunched, it can then check on the status of those transfers.

Using the File Picker

Although the File Picker doesn’t sound all that glamorous, it’s actually, to my mind, one of the coolest features in Windows 8. “Wait a minute!” you say, “How can a UI to pick a file or folder be, well, cool!” The reason is that this is the place where the users can browse and select from their entire world of data. That world includes not only what’s on their local file system or the local network, but also any data that’s made available by what are called file picker providers. These are apps that specifically take a library of data that’s otherwise buried behind a web service, within an app’s own database, or even generated on the fly, and makes it appear as if it’s part of the local file system.

Think about this for a moment (as I invited you to do way back in Chapter 1). When you want to work with an image from a photo service like Flickr or Picasa, for example, what do you typically have to do? First step is to download that file to the local file system within some app that gives you an interface to that service (which might be a web app). Then you can make whatever edits and modifi-cations you want, after which you typically need to upload the file back to the service. Well, that’s not so bad, except that it’s time consuming, forces you to switch between multiple apps, and eventually litters your system with a bunch of temporary files, the relationship of which to your online files is quickly forgotten.

Having a file picker provider that can surface such data directly, both for reading and writing, eliminates all those intermediate steps, and eliminates the need to switch apps. This means that a provider for a photo service makes it possible for other apps to load, edit, and save online content as if it all existed on the local file system. Consuming apps don’t need to know anything about those other services, and they automatically have access to more services as more provider apps are installed. What’s more, providers can also make data that isn’t normally stored as files appear as though they are. For example, the Windows 8 Camera app is a file picker provider that lets you can activate your camera, take a picture, and have it returned as if you loaded it from the file system. All of this gives users a very natural means to flow in and out of data no matter where it’s stored. Like I said, I think this is a very cool feature!

We’ll look more at the question of providers in Chapter 12. Our more immediate concern is how we make use of these file pickers to obtain a StorageFile or StorageFolder object.

The File Picker UI

Before looking at the code, let’s familiarize ourselves with the file picker UI itself. When invoked, you’ll see a full-screen view like that in Figure 8-7, which shows the picker in single-selection mode with a “thumbnail” view. In such a view, items are shown as images in a ListView with a rich tooltip control appearing when you hover over an item. In a way, the file picker itself is like an app that’s invoked for this purpose, and it’s designed to be beautiful and immersive just like other Windows Store apps.

In Figure 8-7, the Pictures heading shows the current location of the picker. The Sort By Name drop-down list lets you choose other sorting criteria, and the drop-down list next to the Files header lets you choose other locations, as shown in Figure 8-8. These locations include other areas of the file system (though never protected areas like the Windows folder or Program Files), network locations, and other provider apps.

images

FIGURE 8-7 A single-selection file picker on the Pictures library in thumbnail view mode, with a hover tooltip showing for one of the items (the head of the Sphinx) and the selection frame showing on another (the Taj Mahal).

images

FIGURE 8-8 Selecting other locations in which to browse files; notice that apps are listed along with file system locations.

Choosing another file system location navigates there, of course, from which you can browse into other folders. Selecting an app, on the other hand, launches that app through the file picker provider contract. In this case it appears within a system-provided (but app-branded) UI like that shown in Figure 8-9. Here the drop-down list next to the heading lets you switch back to other picker locations, and the Open and Cancel buttons act as they do for other picker selections. In short, a provider app really is just an extension to the File Picker UI, but a very powerful one at that. And ultimately such an app just returns an appropriate StorageFile object that makes its way back to the original app. It’s quite a lot happening with just a single call to the file picker API!

images

FIGURE 8-9 The camera app invoked through the file picker provider contract. Where did that nuthatch come from?

The file picker has a couple of other modes. One is the ability to select multiple files—even from different apps!—as shown in Figure 8-10, where all the selections are placed into what’s called the basket on the bottom of the screen. The picker can also be used to select a folder, as shown in Figure 8-11 (provider apps aren’t shown in this case), or a save location and filename, as shown in Figure 8-12.

images

FIGURE 8-10 The file picker in multiselect mode with the selection basket at the bottom. What shown here is also the “list” view mode that’s set independently from the selection mode.

images

FIGURE 8-11 The file picker used to select a folder—notice that the button text changed and a preview of the folder contents appear on the right.

images

FIGURE 8-12 The file picker used to select a save location and filename.

The File Picker API (and a Few Friends)

Now that we’ve seen the visual results of the file picker, let’s see how we invoke it from our app code through the API in Windows.Storage.Pickers. All the images we just saw came from the File picker sample, so we’ll also use that as the source of our code.

For starters, Scenario 1 in its pickSinglePhoto function (js/scenario1.js) uses the picker to obtain a single StorageFile for opening (reading and writing):


function pickSinglePhoto() {
    // Verify that we are currently not snapped, or that we can unsnap to open the picker
    var currentState = Windows.UI.ViewManagement.ApplicationView.value;
    if (currentState === Windows.UI.ViewManagement.ApplicationViewState.snapped &&
        !Windows.UI.ViewManagement.ApplicationView.tryUnsnap()) {
        // Fail silently if we can't unsnap
        return;
    }

    // Create the picker object and set options
    var openPicker = new Windows.Storage.Pickers.FileOpenPicker();
    openPicker.viewMode = Windows.Storage.Pickers.PickerViewMode.thumbnail;
    openPicker.suggestedStartLocation =
        Windows.Storage.Pickers.PickerLocationId.picturesLibrary;

    // Users expect to have a filtered view of their folders depending on the scenario.
    // For example, when choosing a documents folder, restrict the filetypes to documents
    // for your application.
    openPicker.fileTypeFilter.replaceAll([".png", ".jpg", ".jpeg"]);

    // Open the picker for the user to pick a file
    openPicker.pickSingleFileAsync().done(function (file) {
        if (file) {
            // Application now has read/write access to the picked file
        } else {
            // The picker was dismissed with no selected file
        }
    });
}

As you can see, you should not try to invoke the File Picker when in snapped view; this will, like the Settings Pane, cause an exception. You can check for such a condition ahead of time, as shown here, or you can add an error handler within the done at the end.44 In any case, to invoke the picker we create an instance of Windows.Storage.Pickers.FileOpenPicker, configure it, and then call its pick-SingleFileAsync method. The result of pickSingleFileAsync is the file argument given to the completed handler, which will be either a StorageFile object for the selected file or null if the user canceled. This is why you must always check that the picker’s result is not null.

With the configuration, here we’re setting the picker’s viewMode to thumbnail (from the enumeration Windows.Storage.Pickers.PickerViewMode), resulting in the view of Figure 8-7. The other possibility here is list, which gives a view like Figure 8-10.

We also set the suggestedStartLocation to the picturesLibrary, which is a value from the Windows.Storage.Pickers.PickerLocationId enumeration; other possibilities are documentsLibrary, computerFolder, desktop, downloads, homeGroup, musicLibrary, and videosLibrary, basically all the other locations you see in Figure 8-8. Note that using these locations does not require you to declare capabilities in your manifest because by using the picker, the user is giving consent for you to access those files. If you check the manifest in this sample, you’ll see that no capabilities are declared at all.

The one other property we set is the fileTypeFilter (a FileExtensionVector object) to indicate the type of files we’re interested in (PNG and JPEG). Beyond that, the FileOpenPicker also has a commitButtonText property that sets the label of the primary button in the UI (the one that’s not Cancel), and settingsIdentifier, a means to essentially remember different contexts of the file picker. For example, an app might use one identifier for selecting pictures, where the starting location is set to the pictures library and the view mode to thumbnails, and another id for selecting documents with a different location and perhaps a list view mode.

This sample, as you can also see, doesn’t actually do anything with the file once it’s obtained, but it’s quite easy to see what we might do. We can, for instance, simply pass the StorageFile to URL.createObjectURL and assign the result to an img.src property for display. The same thing could be done with audio and video, possibilities that are all demonstrated in Scenario 1 of the Using a blob to save and load content sample I mentioned earlier in this chapter. That sample also shows reading the file contents through the HTML FileReader API alongside the other WinRT and WinJS APIs we’ve seen. You could also transcode an image (or other media) in the StorageFile to another format (as we’ll see in Chapter 10), retrieve thumbnails as shown in the File and folder thumbnail sample, or use the StorageFile methods to make a copy in another location, rename the file, and so forth. But from the file picker’s point of view, its particular job was well done!

Returning now to the file picker sample, picking multiple files is pretty much the same story as shown in the pickMultipleFiles function of js/scenario2.js. Here we’re using the list view mode and starting off in the documentsLibrary. Again, these start locations don’t require capability declarations in the manifest:

function pickMultipleFiles() {
    // Verify that we are currently not snapped, etc... (some code omitted)

    // Create the picker object and set options
    var openPicker = new Windows.Storage.Pickers.FileOpenPicker();
    openPicker.viewMode = Windows.Storage.Pickers.PickerViewMode.list;
    openPicker.suggestedStartLocation =
        Windows.Storage.Pickers.PickerLocationId.documentsLibrary;
    openPicker.fileTypeFilter.replaceAll(["*"]);

    // Open the picker for the user to pick a file
    openPicker.pickMultipleFilesAsync().done(function (files) {
        if (files.size > 0) {
            // Application now has read/write access to the picked file(s)
        } else {
            // The picker was dismissed with no selected file
        }
    });
}

When picking multiple files, the result of pickMultipleFilesAsync is a FilePickerSelectedFilesArray object, which you can access like any other array using [ ] (though it has limited methods otherwise).

Scenario 3 of the sample shows a call to pickSingleFolderAsync, where the result of the operation is a StorageFolder. Here you must indicate a fileTypeFilter that helps users pick an appropriate location where some files of that type exist, or where they can create a new one (js/scneario3.js):

function pickFolder() {
    // Verify that we are currently not snapped... (some code omitted)

    // Create the picker object and set options
    var folderPicker = new Windows.Storage.Pickers.FolderPicker;
    folderPicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.desktop;
    folderPicker.fileTypeFilter.replaceAll([".docx", ".xlsx", ".pptx"]);

    folderPicker.pickSingleFolderAsync().then(function (folder) {
        if (folder) {
            // Cache folder so the contents can be accessed at a later time
            Windows.Storage.AccessCache.StorageApplicationPermissions.futureAccessList
                .addOrReplace("PickedFolderToken", folder);
        } else {
            // The picker was dismissed with no selected file
        }
    });
}

In this example we also see how to save that selected StorageFolder in the Windows.Storage.-AccessCache for future use. Again, by selecting this folder the user has granted the app programmatic access to its contents, but only for the current session. To maintain that access, the app must save the storage item in the futureAccessList of the cache, where it can be later retrieved using the futureAccessList.getFolderAsync, getItemAsync, or getFileAsync methods. As before, refer to Scenario 6 of the File access sample for more on this feature, and note that the AccessCache API also provides for recently used items as well. The key thing to remember here is that for any location outside of your package, app data, or libraries for which you’ve declared access, you must use the AccessCache to maintain access in the future. It won’t work to save a pathname to such locations and attempt to open files again later.

For the final file picker use case, Scenario 4 of the file picker sample creates a FileSavePicker object and calls its pickSaveFileAsync method, resulting in the UI of Figure 8-12:

function saveFile() {
    // Verify that we are currently not snapped... (some code omitted)

    // Create the picker object and set options
    var savePicker = new Windows.Storage.Pickers.FileSavePicker();
    savePicker.suggestedStartLocation =
        Windows.Storage.Pickers.PickerLocationId.documentsLibrary;
    // Dropdown of file types the user can save the file as
    savePicker.fileTypeChoices.insert("Plain Text", [".txt"]);

    // Default file name if the user does not type one in or select a file to replace
    savePicker.suggestedFileName = "New Document";

    savePicker.pickSaveFileAsync().done(function (file) {
        if (file) {
            // Prevent updates to the remote version of the file until we finish making
            // changes and call CompleteUpdatesAsync.
            Windows.Storage.CachedFileManager.deferUpdates(file);

            // write to file
            Windows.Storage.FileIO.writeTextAsync(file, file.name).done(function () {
                // Let Windows know that we're finished changing the file so the other app
                // can update the remote version of the file.
                // Completing updates might require Windows to ask for user input.
                Windows.Storage.CachedFileManager.completeUpdatesAsync(file)
                    .done(function (updateStatus) {
                        if (updateStatus ===
                            Windows.Storage.Provider.FileUpdateStatus.complete) {
                        } else {
                            // ...
                        }
                    }
                });
            });
        } else  {
            // The picker was dismissed
        }
    });
}

The FileSavePicker has many of the same properties as the FileOpenPicker, but it replaces fileTypeFilter with fileTypeChoices (to populate the drop-down list) and includes a suggested-FileName (a string), suggestedSaveFile (a StorageFile), and defaultFileExtension (a string). What’s interesting in the code above are the interactions with the Windows.Storage.CachedFileManager. This object helps file picker providers know when they should synchronize local and remote files, which would be necessary when a file consumer saves new content as we see here. From the consumer side, what we see here is a typical pattern for files obtained from the file picker (or the access cache if saved there in a previous session): we simply need to let the CachedFileManager know that we’re writing to the file and tell it when we’re done. Of course, this isn’t needed when working with files that you know are local, such as those in your AppData folders. We’ll learn more about this mechanism in Chapter 12 when we look at the provider side.

Media Libraries

Now that we’ve seen understood the capabilities of the file picker, we can turn our attention to the other libraries. But before you start checking off capabilities in your manifest, pause for a moment to ask this: are those capabilities actually needed? The file pickers provide very extensive access to all these libraries without needing any capabilities at all. Through the pickers you can have the user select one or more files to open, manipulate, and save; the user can give you access to a folder; and the user can indicate a new filename in which to save user data.

You only need specific library access if you’re going to work within any of these libraries outside of the file picker. For example, if you want to enumerate the contents of the Pictures or Music folder to display a list in a ListView or FlipView control, as we did in Chapter 5, you do need to declare a capability.

To be even more specific, without going through the file picker there is only one way to gain programmatic access to a media library: obtaining a StorageFolder from the Windows.-Storage.KnownFolders object. For media, the applicable properties here are picturesLibrary, musicLibrary, and videosLibrary. Without the appropriate capability, trying to retrieve one of these will throw an access denied exception.

If you don’t need to access KnownFolders, then, you don’t need to declare the capabilities! And remember that since all your declared capabilities are listed for your app in the Windows Store and might make consumers think twice about installing your app, fewer is definitely better.

That said, if you do decide to access media libraries directly, your work there involves StorageFolder and StorageFile objects pretty much like any other storage location. One difference, however, is that you can work with the metadata often included with media files; we’ll see a little more of this in Chapter 10.

Documents and Removable Storage

As with the media libraries, programmatic access to the user’s documents folder as well as removable storage devices are controlled by capability declarations. It’s important once again to understand that both of these capabilities also require you to declare file type associations, meaning that you cannot simply enumerate the contents of these folders directly or write whatever files you want therein. Put another way, going directly to these folders—through Windows.Storage.KnownFolders.-documentsLibrary and removableDevices, both of which are StorageFolder objects—just for a limited set of file types is useful only in very particular scenarios. For the documents library, in fact, the documentation states that “the only acceptable use of the [capability] is to support the opening of embedded content within another document.” The Windows Store will also ask you to justify your declaration of the capability directly and also requires that you have a “company account” on the Windows Store, not just an individual account.

It’s more likely that you simply want to allow the user to open or save a file in these locations, or enumerate their contents, in which case all you need is the file picker. This way you don’t need to associate your app with specific tile types, which also says that your app is available to service such files at any time.

For example, the Removable storage sample, in order to demonstrate access to removable devices, declares associations with .gif, .jpg, and .png files. As a result, it shows up in Open With lists like the context menu of Windows Explorer on the desktop and the default program selector:

images

The same is also true for documents (see the File access sample again), so unless your app is again positioned to service those file types, you probably don’t need these capabilities.

How exactly to declare file type associations is a form of contracts, so we’ll cover the details in Chapter 12.

Rich Enumeration with File Queries

To enumerate files within a particular location (capabilities aside), you employ what’s called a file query or, simply, a search. A file query is exactly what Windows Explorer on the desktop uses to search the file system and can involve file contents as well as any number of other properties/metadata. These queries involve what are known as Advanced Query Syntax (AQS) strings that are capable of identifying and describing as many specific criteria you desire. As such, the whole topic is somewhat beyond the scope of this book, but we can at least touch on how WinRT makes the power of file queries available to apps through the Windows.Storage.Search. One foot in the deep rabbit hole will be enough!

Indeed, there are literally thousands of options you can use in an AQS string, because they are built from any number of Windows properties such as System.ItemDate, System.Author, System.Keywords, System.Photo.LightSource, and so on.45 Each property can contain a target value such as System.-Author(Patrick or Bob) and System.ItemType: "mp3", and terms can be combined with AND, OR, and NOT operators. We’ll see many more examples in Chapter 10, where we can use queries to retrieve collections of files in many different “shapes” such as a flat list, a hierarchy, and various sort orders, including those oriented around media properties. In addition, file queries also provide for obtaining thumbnails as well as automatic retrieval of album art for music.

Here, let’s concentrate on understanding how file queries work, starting with the basics that are demonstrated in the FileQuery example included with this chapter’s companion content. This example is a copy of the Programmatic file search sample in the Windows SDK, which itself has only one scenario oriented on the music library that lets you enter in an AQS string directly. However, this isn’t always what you’ll be using in an app, so I wanted to show many other variations.

Queries always start with a StorageFolder, whose createFileQuery[WithOptions], createFolderQuery[WithOptions], and createItemQuery[WithOptions] methods (6 total) provide for enumerating files, folders, or both, within whatever folder the StorageFolder is attached to. The simplest queries are created with the base StorageFolder.create* methods and no parameters:

folder.createFileQuery();
folder.createFolderQuery();
folder.createItemQuery();

The first two methods here are actually just shortcuts for the one-parameter variants with the same names, where that parameter is a value from the Windows.Storage.Search.CommonFileQuery or CommonFolderQuery enumerations. These shortcut versions just use the defaultQuery value for a simple alphabetical, shallow enumeration of the folder contents. createItemQuery, for its part, has only this one form.

Creating a query itself doesn’t actually enumerate anything until you ask it to through an async method: for file queries the method is getFilesAsync, for folders it’s getFoldersAsync, and for items it’s getItemsAsync. (See a pattern here?) So, in Scenario 2 of the FileQuery example, I have these three functions attached to buttons:

function fileQuery() {
    var query = picturesLibrary.createFileQuery();
    SdkSample.showResults(query.getFilesAsync());
}

function folderQuery() {
    var query = picturesLibrary.createFolderQuery();
    SdkSample.showResults(query.getFoldersAsync());
}

function itemQuery() {
    var query = picturesLibrary.createItemQuery();
    SdkSample.showResults(query.getItemsAsync());
}

where the SdkSample.showResults function in js/default.js just creates a listing of the items in the collection. Running this sample, you’ll see a list of those files and/or folders in your Pictures library.

Tip The actual object types returned by these create*Query APIs are StorageFileQueryResult, StorageFolderQueryResult, and StorageItemQueryResult, all in the Windows.Storage.Search namespace. These all provide some additional properties like folder, methods like findStartIndexAsync and getItemCountAsync, and events like optionschanged and contentschanged (both WinRT events). The latter event especially is something you can use to monitor changes to the file system that affect query results.

Beyond this shallow default behavior, file and folder queries have many other possibilities as expressed in the CommonFileQuery and CommonFolderQuery enumerations:

CommonFileQuery: orderByName, orderByTitle, orderByDate, orderByMusic-Properties, and orderBySearchRank.

CommonFolderQuery: groupByType, groupByTag, groupByAuthor, groupByYear, groupByMonth, groupByArtist, groupByComposer, groupByGenre, groupByPublishedYear, and groupByRating.

Clearly, the effect of these choices depends on the queried items actually containing metadata that supports the ordering or grouping, but it is allowable to query all folders for all types of files and folders. To demonstrate this, Scenario 3 of the FileQuery example lets you choose the music, pictures, or videos library. Then you can choose whether to query files or folders, choose the common query to apply, and run a search to see the results. Note that using orderBySearchRank with files isn’t really meaningful in this context because it’s meant to work with AQS-based searches. We’ll see this a little later. (Also—call me a slacker!—the results of a grouped folder query isn’t very interesting when one doesn’t group the display output, but for an example of that you can refer to Scenario 2 of the Folder enumeration sample.)

The code in js/scenario3.js is pretty much just the mechanics of mapping your UI selections to either createFileQuery or createFolderQuery with the right parameters, so there’s no need to look at most of it here. One important piece is the use of the isCommonFileQuerySupported and isCommonFolderQuerySupported methods of StorageFolder. These are used to test whether the current folder will actually support the particular query you want to try:

if (folder.isCommonFileQuerySupported(selectedQuery)) {
    query = folder.createFileQuery(selectedQuery);
    if (query) {
        promise = query.getFilesAsync();
    }
}

You’ll find that when running the sample in the media libraries, at least, all the common file and folder queries are supported, but that might not be true for all StorageFolder objects you might encounter. Remember, for example, that the folder picker might give you a StorageFolder from a provider whose data is off in some online service or a database, in which case certain queries might not work.

A similar method, StorageFolder.areQueryOptionsSupported, also exists to tests support for custom queries beyond the common ones. A custom query is described by a Windows.Storage.-Search.QueryOptions object (the common queries are just prepopulated instances of these) and is created by passing such an object to the createFileQueryWithOptions, createFolderQuery-WithOptions, and createItemQueryWithOptions.

A QueryOptions is generally created from scratch using the new operator, after which you populate its properties. You can also use new QueryOptions(<CommonFolderQuery>) to retrieve the object for one of the common folder queries, and new QueryOptions(<CommonFileQuery> [, <file type filter>]) to do the same for common file queries. In this latter case, an optional array of file types can also be given; this is a shortcut to quickly customize a common query with a specific set of file types. Without it, the filter is set to "*" by default. That is, if you wanted to just find .mp3 files in your music library ordered by title, you would use this kind of code (see js/scenario4.js in the FileQuery example):

var musicLibrary = Windows.Storage.KnownFolders.musicLibrary;
var options = new Windows.Storage.Search.QueryOptions(
    Windows.Storage.Search.CommonFileQuery.orderByTitle, [".mp3"]);

if (musicLibrary.areQueryOptionsSupported(options)) {
    var query = musicLibrary.createFileQueryWithOptions(options);
    SdkSample.showResults(query.getFilesAsync());
}

If you create a QueryOptions from scratch, you can set a number of options. The more general or basic ones are as follows:46

fileTypeFilter An vector of strings that describe the desired file type extensions, as in ".mp3". The default is an empty list (no filtering).

folderDepth Either Windows.Storage.Search.FolderDepth.shallow (the default) or deep.

indexerOption A value from Windows.Storage.Search.IndexerOption, which is one of useIndexerWhenAvailable, onlyUseIndexer (limit the search to indexed content only), and doNotUseIndexer (query the file system directly bypassing the indexer). As the latter is the default, you’ll typically want to explicitly set this property to useIndexerWhenAvailable.

sortOrder A vector of Windows.Storage.Search.SortEntry structures that each contain a Boolean named ascendingOrder (false for descending order) and a propertyName string. Each entry in the vector defines a sort criterion; these are applied in the order they appear in the vector. An example of this will be given a little later.

Three of the QueryOptions properties then apply to searches with AQS strings:

applicationSearchFilter An AQS string.

userSearchFilter Another AQS string.

language A string containing the BCP-47 language tag associated with the AQS strings.

When the query is built through a method like createFileQueryWithOptions, the application and user filter strings here are combined. What this means is that you can separately manage any filter you want to apply generally for your app (applicationSearchFilter) from user-supplied search terms (userSearchFilter). This way you can enforce some search filters without requiring the user to type them in, and without always having to combine strings yourself.

As noted before, the CommonFileQuery.orderBySearchRank query is meaningful only when combined with an AQS string, which is to say that keyword-based searches return ranked results for which this common file query would apply. Returning to Scenario 1 of the Programmatic file search sample, then, we see how it uses this ordering along with the userSearchFilter property:

var musicLibrary = Windows.Storage.KnownFolders.musicLibrary;
var options = new Windows.Storage.Search.QueryOptions(
    Windows.Storage.Search.CommonFileQuery.orderBySearchRank, ["*"]);
options.userSearchFilter = searchFilter;
var fileQuery = musicLibrary.createFileQueryWithOptions(options);

On my machine, where I have a number of songs with “Nightingale” in the title, as well as an album called “Nightingale Lullaby,” a search using the string "Nightingale" System.ItemType: "mp3" in the above code gives me results that look like this in the sample:

images

This shows that the search ranking favors songs with “Nightingale” directly in the title, but also includes those from an album with that name.

My search string here, by the way, shows how you might use the applicationSearchFilter and userSearchFilter properties together. If my app was capable of working only with mp3 or some other formats, I could store "System.Item.Type: 'mp3'" in applicationSearchFilter and store user-provided terms like "Nightingale" in userSearchFilter. This way I avoid having to join them manually in my code.

Beyond the properties that you set within a QueryOptions object, it also has some information and capabilities of its own. The groupPropertyName, for one, is a string property that indicates the type of property that the query is being grouped by. You can also retrieve the query options as a string using the saveToString method and recreate the object from a string using loadFromString (that is, the analog of JSON.stringify and JSON.parse).

The setPropertyPrefetch method goes even deeper still, allowing you to indicate a group of file properties that you want to optimize for fast retrieval—they’re accessed through the same APIs as file properties in general, but they come back faster, meaning that if you’re displaying a collection of files in a ListView using a custom data source with certain properties from enumerated files, you’d want to set those up for prefetch so that the control renders faster. (The WinJS.UI.StorageDataSource does this already.) Similarly, setThumbnailPrefetch tells Windows what kinds of thumbnails you want to include in the enumeration—again, you can ask for these without setting the prefetch, but they come back faster when you do. This helps you optimize the display of a file collection.47

We briefly saw similar usage of thumbnail properties back in Chapter 5, when we took advantage of a shortcut to the pictures library with WinJS.UI.StorageDataSource and could specify a thumbnail size option:

myFlipView.itemDataSource = new WinJS.UI.StorageDataSource("Pictures",
    { requestedThumbnailSize: 480 });

A more general example that also includes the QueryOptions.sortOrder vector can be found in the StorageDataSource and GetVirtualizedFilesVector sample, which got a footnote in Chapter 5. In its js/scenario2.js we see the creation of a QueryOptions from scratch, setting up two sortOrder criteria, and setting up thumbnail options in the data source:

function loadListViewControl() {
    // Build datasource from the pictures library
    var library = Windows.Storage.KnownFolders.picturesLibrary;
    var queryOptions = new Windows.Storage.Search.QueryOptions;
    // Shallow query to get the file hierarchy
    queryOptions.folderDepth = Windows.Storage.Search.FolderDepth.shallow;
    queryOptions.sortOrder.clear();
    // Order items by type so folders come first
    queryOptions.sortOrder.append({ascendingOrder: false, propertyName: "System.IsFolder"});
    queryOptions.sortOrder.append({ascendingOrder: true, propertyName: "System.ItemName"});
    queryOptions.indexerOption =
        Windows.Storage.Search.IndexerOption.useIndexerWhenAvailable;

    var fileQuery = library.createItemQueryWithOptions(queryOptions);
    var dataSourceOptions = {
        mode: Windows.Storage.FileProperties.ThumbnailMode.picturesView,
        requestedThumbnailSize: 190,
        thumbnailOptions: Windows.Storage.FileProperties.ThumbnailOptions.none
    };

    var dataSource = new WinJS.UI.StorageDataSource(fileQuery, dataSourceOptions);

    // Create the ListView...
};

If you’re really interested in digging deeper here, you can look at how StorageDataSource sets up file queries; just search for this class in the ui.js file of WinJS and you’ll find it. Along the way, you’ll run into one more set of WinRT APIs—perhaps the bottom of the hole!—that I wanted to mention before wrapping up this subject: Windows.Storage.BulkAccess. These actually exist solely for use by StorageDataSource and are not intended for direct use in apps. Even if you create your own data source or collection control, it’s best to just use the enumeration and prefetch APIs we’ve already discussed, as they give identical performance.

Here My Am! Update

To bring together some of the topics we’ve covered in this chapter, the companion content includes another revision of the Here My Am! app with the following changes and additions (mostly to pages/home/home.js unless noted):

• It now incorporates the Bing Maps SDK so that the control is part of the package rather than loaded from a remote source. This eliminates the iframe we’ve been using to host the map, so all the code from html/map.html can move into js/default.js. Note that to run this sample in Visual Studio you need to download and install the SDK yourself.

• Instead of copying pictures taken with the camera to app data, those are now copied to a HereMyAm folder in the Pictures library. The Pictures Library capability has been declared.

• Instead of saving a pathname to the last captured image file, which is used when the app is terminated and restarted, the StorageFile is saved in Windows.Storage.AccessCache to guarantee future programmatic access.

• An added appbar command allows you to use the File Picker to select an image to load instead of relying solely on the camera. This also allows you to use a camera app, if desired. Note that we use a particular settingsIdentifier with the picker in this case to distinguish from the picker for recent images.

• Another appbar command allows you to choose from recent pictures from the camera. This defaults to our folder in the Pictures library and uses a different settingsIdentifier.

• Additional commands for About, Help, and a Privacy Statement are included on the Settings pane using the WinJS.Application.onsettings event (see js/default.js). The first two display content from within the app whereas the third pulls down web content in an iframe; all the settings pages are found in the html folder of the project.

What We’ve Just Learned

• Statefulness is important to Windows Store apps, to maintain a sense of continuity between sessions even if the app is suspended and terminated.

• App data is session, local, temporary, and roaming state that is tied to the existence of an app; it is accessible only by that app.

• User data is stored in locations other than app data (such as the user’s music, pictures, videos, and documents libraries, along with removable storage) and persists independent of any given app, and multiple apps might be able to open and manipulate user files.

• App data is accessed through the Windows.Storage.ApplicationData API and accommodates both structured settings containers as well as file-based data. Additional APIs like IndexedDB and HTML5 localStorage are also available.

• It is important to version app state, especially where roaming is concerned, as versioning is how the roaming service manages what app state gets roamed to which devices based on what version apps are looking for.

• The size of roaming state is limited to a quota (provided by an API), otherwise Windows will not roam the data. Services like SkyDrive can be used to roam larger files, including user data.

• The typical roaming period is 30 minutes or less. A single setting or composite named “HighPriority,” so long as it’s under 8K, will be roamed within a minute.

• The StorageFolder and StorageFile classes in WinRT are the core objects for working with folders and files. All programmatic access to the file system begins, in fact, with a StorageFolder. Otherwise, the user can point to files and folders through the file picker API, which is really the first choice for file access.

• Blobs are useful aids in working with files, as are the WinRT APIs in the Windows.Storage.-FileIO and PathIO classes. WinJS offers some simplified methods for reading and writing text files (especially in conjunction with app state), and the HTML5 FileReader is supported.

• WinRT offers encryption services through Windows.Security.Cryptography, as well as a built-in compression mechanism in Windows.Storage.Compression.

• To use the Settings pane, an app populates the top-level pane provided by Windows with specific commands. Those commands map to handlers that either open a hyperlink (in a browser) or display a settings flyout using the WinJS.UI.SettingsFlyout control. Those flyouts can contain any HTML desired, including iframe elements that load remote content.

• Access to user data folders, such as media libraries, documents, and removable storage, is controlled by manifest capabilities. Such capabilities need be declared only if the app needs to access the file system in some way other than using the file picker.

• The file picker is the way that users can select files from any safe location in the file system, as well as files that are provided by other apps (where those files might be remote, stored in a database, or otherwise not present as file entities on the local file system). The ability to select files directly from other apps—including files that another app might generate on demand—is one of the most convenient and powerful features of Windows Store apps.

StorageFolder objects provide a very rich and extensive capability to query and search its contents through file queries. These queries can be simple to complex and can employ Advanced Query Syntax (AQS) search strings.