Silverlight for Windows Phone Programming Tip – Navigation

When using the Silverlight for Windows Phone APIs to navigate from one page to another, it is necessary to use the Navigate method on the PhoneApplicationPage instance’s NavigationService property.  When making this call, it is important to note the required Uri Syntax, as follows:

Navigating to a page in the same assembly:

NavigationService.Navigate(new Uri("/Folder(s)/TargetPage.xaml", UriKind.relative));

Navigating to a page in another assembly:

NavigationService.Navigate(new Uri("/AssemblyName;component/Folder(s)/TargetPage.xaml", UriKind.Relative));

The current MSDN Documentation (update date of 1/28/2001) for the Navigate method does not include any text that specifies the requirements for the syntax or the Uri, so here goes my attempt to provide the missing content:

  • The provided Uri must start with a forward slash (/), indicating the content is local to the Xap file.  Failure to include the leading slash will result in an ArgumentException (details below) being thrown.
  • The UriKind must be specified as UriKind.Relative (or URIKindRelativeOrAbsolute, but why ask for trouble?)  Omitting the UriKind uses the default value of URIKind.Absolute, which yields the same ArgumentException
  • To navigate to a page in another assembly contained within the same Xap file, the syntax must include the Assembly Name for the assembly that contains the page, then a semicolon and the word “component”, followed by the folder path to the page.
    • The leading slash and the specification of a Relative Uri are still required, with the same consequences if omitted.
    • Omitting the word “component” results in an InvalidOperationException (No Xaml was found at the location…)

The description contained in the Argument exception is actually quite helpful – it reads “Navigation is only supported to relative URIs that are fragments, or begin with ‘/’, or which contain ‘;component.”  However, you have to first fail in your attempts to navigate and be in a position to trap and analyze the exception for it to be useful.

Making small and subtle mistakes in the navigation Uri is quite easy to do…not only is missing relevant documentation missing as noted above, but this API also falls quite short in the “Pit of Success” category at the expense of matching up with the Navigation API in regular Silverlight (I have witnessed good presenters’ phone demos get derailed and lose precious time because of some simple omissions in this regard.)  A better alternative would have been to have offered a way to avoid the specific nuances of the API in favor of phone-specific methods.  (Jeremy’s Ultra-Light Windows Phone 7 MVVM Framework accomplishes something very close/similar.)  Fortunately, if you are doing a lot of navigation in your app and would like to include a set of phone-specific NavigateToPhonePage calls which figure out and correct the necessary Uris for you, there is a quick way to do so – using Extension Methods.  A set of simple & helpful starter Phone Navigation extension methods follows:

public static class PhoneNavigationServiceExtensions
{     
      public static void NavigateToPhonePage(this NavigationService navigationService, String page)     
      {          
           if (navigationService == null) throw new ArgumentNullException("navigationService");          
           if (!page.StartsWith("/")) page = "/" + page;  //Compensate for lack of leading slash          
           navigationService.Navigate(new Uri(page, UriKind.Relative)); //Build the Uri, force it to be Relative.
      }

      public static void NavigateToLocalPhonePage(this NavigationService navigationService, String page)
      {
           NavigateToPhonePage(navigationService, page);
      }     

      public static void NavigateToExternalPhonePage(this NavigationService navigationService, String assemblyName, String page)     
      {          
           if (!page.StartsWith("/")) page = "/" + page;  //Compensate for lack of leading slash in the page          
           NavigateToPhonePage(navigationService, String.Format("{0};component{1}", assemblyName, page));     
      }
}

Given these extensions, the following navigation calls all work without a need to specify the UriKind, and with varying inclusions and omissions of the forward slashes:

// Using NavigateToLocalPhonePage requires nothing more than the path to the page's xaml file
NavigationService.NavigateToLocalPhonePage("/Folder(s)/TargetPage.xaml");
NavigationService.NavigateToLocalPhonePage("Folder(s)/TargetPage.xaml");

// Using NavigateToExternalPhonePage calls out the need for the assembly name and the page's xaml file path
NavigationService.NavigateToExternalPhonePage("/WindowsPhoneClassLibrary1", "/Folder(s)/TargetPage.xaml");
NavigationService.NavigateToExternalPhonePage("WindowsPhoneClassLibrary1", "Folder(s)/TargetPage.xaml");

// Using the NavigateToPage method directly works for either, but the External page must be specified correctly
NavigationService.NavigateToPhonePage("Folder(s)/TargetPage.xaml");
NavigationService.NavigateToPhonePage("WindowsPhoneClassLibrary1;component/Folder(s)/TargetPage.xaml");

A Matter of State, Part 3

The previous 2 posts discussed using the Page and Application State Dictionaries to restore state following the application being tombstoned, as well as some other potential uses for the Application State Dictionary.  This final post in the series will cover the user of Isolated Storage from Windows Phone applications.

Isolated Storage Basics
Isolated Storage provides a virtual file system that allows an application (and in some cases applications) access to an (ahem) isolated area of persistent storage, usually disk-based.  The precise location is hidden from applications and is not meant to be human-readable/accessible.  The technique of using Isolated Storage to preserve state is one that is available across all flavors of .Net – there is support for Isolated Storage in the .Net Framework, in the Silverlight Runtime (both on the PC and the Mac), and in Silverlight for Windows Phone.  While many of the mechanics of using Isolated Storage APIs are similar between the platforms, there are some distinctions in Windows Phone that make its support for Isolated Storage unique.
At its core, data stored in Isolated Storage is placed in a scoped area called a Store.  Each runtime described above has access to a different collection of scopes for the stores, with .Net having access to the most (User, Domain, Assembly, Roaming, Machine, Application), and Silverlight having access to just two – Site and Application.  The Site scope allows shared storage access to all Silverlight applications on the same web domain, and the Application scope is identified by each unique Silverlight XAP file.
In Silverlight for Windows Phone, the Silverlight applications are not hosted on any web site, so the only Isolated Storage scope available in phone applications is per Application.  One important implication of this is that there is currently no way of sharing or exchanging data between applications via the phone file system.  Having gone over the concept of tombstoning, there’s also an implication that the technique of using Local Connections is not available for inter-application communication (if only one application can be running at a time, there’s nobody to communicate with.)  Taking this all one step further, the only way to communicate between different applications in Windows Phone is by using some form of internet-based storage.
The following code shows the basic procedure for writing data to Isolated Storage:
private void WriteData()
{
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
{
// Get the directories in the current Store
String[] directoryNames = store.GetDirectoryNames(“search pattern”);


// Get the files in the given directory path
String[] fileNames = store.GetFileNames(“search pattern”);
//Maybe create one or more directories
store.CreateDirectory(“SomeNewDirectory”);
// Open a file stream (normal File.Open behavior)
using (IsolatedStorageFileStream fileStream = store.OpenFile(“file path”FileMode.Create))
{
using (StreamWriter writer = new StreamWriter(fileStream))
{
writer.WriteLine(“Some Data”);
}
}
}
}

  • Use the GetUserStoreForApplication call to get a reference to the application’s Isolated Storage file store
  • Using the store reference, it is possible to obtain a list of directories and/or files within the current store, as well as to create files and directories
  • Note that the process for creating files is the same as for regular files (specifying FileMode, etc.)
  • The result of an opened file is an IsolatedStorageFileStream object, which inherits from the FileStream class.
  • Once a reference to the IsolatedStorageFileStream object is available, code can be written against it as it can for pretty much any FileStream.  The example above wraps the stream with a StreamWriter which exposes a WriteLine that can be used to write a line of text into the stream (and hence the underlying file.)
  • Note that using blocks are being used to perform the necessary cleanup on Disposable objects throughout the process.
The following code shows the basic procedure for reading code from Isolated Storage:
private void ReadData()
{
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
{
if (store.FileExists(“file path”))
{
using (IsolatedStorageFileStream fileStream = store.OpenFile(“file path”FileMode.Open))
{
using (StreamReader reader = new StreamReader(fileStream))
{
String lineOfText = String.Empty;
while (null != (lineOfText = reader.ReadLine()))
{
DoSomethingInterestingWithText(lineOfText);
}
}
}
}
}
}
  • Get a reference to the application’s Isolated Storage file store
  • Using the store reference, check to see fi the desired file exists
  • If the file exists, open the file for reading, which returns an IsolatedStorageFileStream object, which inherits from the FileStream class.
  • Once a reference to the IsolatedStorageFileStream object is available, code can be written against it as it can for pretty much any FileStream.  The example above wraps the stream with a StreamWriter which exposes a ReadLine that can be used to read a line of text at a time from the stream (and hence the underlying file.)
Within the System.IO.IsolatedStorage namespace, there is a “helper class” that reduces some of the work required for routine Isolated Storage tasks.  Much like the Application and Page State Dictionaries, the IsolatedStorageSettings class exposes a Dictionary of objects that uses string values for keys.  The IsolatedStorageSettings class is accessible as a singleton through the IsolatedStorageSettings.ApplicationSettings property (note that “regular Silverlight” also exposes IsolatedStorageSettings.SiteSettings for site-scoped storage.)
The following code shows writing and reading from the ApplicationSettings dictionary:
private void WriteSettingsData()
{
IsolatedStorageSettings.ApplicationSettings[“key”] = value;
}
private void ReadSettingsData()
{
if (IsolatedStorageSettings.ApplicationSettings.Contains(“key”))
{
value = IsolatedStorageSettings.ApplicationSettings[“key”];
}
}
Many possibilities are available for storing and retrieving data through Isolated Storage beyond simply reading and writing text using the StreamWriter and/or IsolatedStorageSettings.  These range from using Xml to hold serialized objects through custom database implementations, including my Wintellect colleague Jeremy Likness’s
Sterling Object-Oriented database and the Codeplex implementation/port of Sqlite.  Like most file systems, there are concerns regarding the quantity and size of items in any given folder, and there is a great discussion here on the performance behavior of Isolated Storage in Windows Phone under load.

Capacity
Another important distinction between Isolated Storage for Silverlight and Isolated Storage for Silverlight for Windows Phone is that whereas there are user quotas in “regular” Silverlight (1 MB max for browser-based apps before the user must be asked if they would like to increase the quota, and 25 MB for out-of-browser apps), there are no storage quotas in place for Silverlight for Windows Phone applications.  Storage space is limited by the amount of storage space available on the device itself.
Not only is there no quota for the amount of storage that any one application can consume, there is also no File Explorer or WinDirStat equivalent for the phone to determine how much space is being consumed by any one application.  Although there’s no way to know which application may be consuming all of the available space on a device, if an application is chosen for deletion, when an application is uninstalled from the phone (locate the shortcut in the application list, hold down the application icon, and in the context menu that appears, choose uninstall) its isolated storage contents are deleted and the space they occupied is recovered.
Figure 1- Prompt When Uninstalling an Application
To determine the total amount of space remaining on disk, the IsolatedStorageFile instance offers an AvailableFreeSpace property.  With “traditional Silverlight”, this returns the amount of space remaining in the current quota.  Since Silverlight for Windows Phone does not have quotas, the AvailableFreeSpace property will return the amount of storage space remaining on the device.
In the following screenshots, an application was created that wrote a large amount of data to Isolated Storage.  A second application was written to show the amount of drive space remaining.  In the first screenshot, the storage application has not yet written its data to disk.  In the second screenshot, it has written data to disk, as can be seen by the reduced amount of available free space remaining.  Finally, in the third screenshot, the storage application has been uninstalled and its storage space has been reclaimed.  (Note that the extra space appearing in the third screenshot is most likely due to the additional space received by the removal of the Silverlight XAP file in addition to the content in Isolated Storage.)
Figure 2- Before Saving Large File
Figure 3- After Saving Large File
Figure 4- After “Big File” Application is Uninstalled
Knowing this about uninstallation, the next logical question usually deals with updating.  When an application is updated (a new version is placed in the Marketplace), the data in Isolated Storage is retained.  It is up to the application developer(s) to handle issues related to the handling of versioning with any previous application versions’ contents in Isolated Storage.

Tombstoning
While Isolated Storage is the only one of the three state-preservation mechanisms discussed that can work across multiple launches of the same application (and hence beyond Tombstoning), it is certainly usable for Tombstoning scenarios, and is absolutely necessary in some cases, such as when the amount of data to be stored exceeds the limitations imposed by the other techniques.  Because of the performance implications of Isolated Storage (discussed in the previous article in the series, ~30% to ~55% slower) and the possibility of larger amounts of data, there are important time limits that need to be discussed.
First of all, as stated here in the MSDN documentation, if an application takes more than 10 seconds to launch, the application may be terminated by the operating system.  Furthermore, the Windows Phone Application Certification Requirements state that in order to pass the certification process, an application must render its first screen “within 5 seconds after launch” (5.2.1a), and must be responsive to user input “within 20 seconds after launch” (5.2.1b)  Finally, an application must conclude the Activated and Deactivated events within 10 seconds. (5.2.3)  As a result, it may be beneficial to consider breaking the content in Isolated Storage into smaller files that are accessed as needed (instead of big-load-up-front), background threads be used for loading large content at startup, and similar consideration be employed when saving data.
With these time considerations in mind, the key application lifetime events include:
  • Launching – Raised when a new instance of the application is launched (and will not be raised if the application is being activated following tombstoning.)
  • Closing – Raised when the application is terminated.  In Silverlight applications, this only occurs when the user uses the Back button past the first page in the application’s BackStack (and will not be raised when the application is being tombstoned.)
  • Deactivated – Raised when the user navigates away from the application (and in most cases, is tombstoned.)
  • Activated – Raised when the user returns to an application after it was deactivated.
Because both Deactivated and Closing (under most circumstances) result in the application being terminated and in-memory state being destroyed, it is important to ensure that state is appropriately saved and restored in both circumstances.  State information retrieved when an application is initially launched is not automatically preserved or restored.  For that reason, it is not atypical to see the Launching/Activated and Closing/Deactivated event handlers call into a common pair of methods (such as RestoreState and SaveState, respectively) to deal with common content.

In Closing
In this series, the posts focused on mechanisms for preserving state in Windows Phone Silverlight applications.  The key concepts presented included:
I hope that this coverage has helped to illustrate the benefits and limitations of each.

New England Code Camp 14 Presentation Materials

I have uploaded the content from my two talks at the New England Code Camp – Introduction to Windows Phone 7 Development with Silverlight and Advanced Windows Phone 7 Development with Silverlight. The content can be found here and here (Slideshare links here and here.) The uploaded content includes:

  • Presentation slides, which include the reference and event links I mentioned during the talk
  • An interactive pdf of the outline I worked off for the talk (Acrobat Reader may be required)
  • The sample code

The demo code was prepared with the RTM version of the Windows Phone Developer Tools, as well as some controls from the Silverlight for Windows Phone Toolkit. To use the Bing Maps demos without the watermark indicating the control needs to be licensed, please go to the Bing Maps Developer portal, register, and put your application key into the properties in the BingMapsKey.cs files.

* Note – when using the Notification Service and Bing Maps Demos from the Advanced topic, be sure to set the solution to use Multiple Startup Projects (PhoneDemo and PhoneDemoService.)

Windows Phone 7 Developer Tools RTM, etc.

With all due respect to Steve Martin, “The new phone tools are here! The new phone tools are here!”

Following up on my recent presentations introducing development for Windows Phone 7 with Silverlight, the release of the RTM version of the Windows Phone 7 to the public today was announced today, along with a couple other key items. First and foremost, the new tools can be found here. The “normal” download is a web-based installer, but there is a tiny link at the bottom of the page for downloading an ISO image. The RTM includes the long awaited (by some) Panorama, Pivot, and Map controls, with Panorama and Pivot being backed by specific starter-project templates in both Visual Studio and Blend. The Panorama control enables the presentation of content on a long horizontal canvas through which the phone display serves as a viewport (think of the Panorama Control as the ruler portion of a slide-rule, and the phone as the central strip.) The Pivot control can be thought as the equivalent of the Tab-Control for the phone. Finally, the Map control presents the Bing Maps Silverlight control to the phone. More information on using Bing Map controls (outside of the phone, but there is some translation…) can be found here.

There are some subtle breaking changes in the new toolkit, and they are outlined in the Release Notes, which are also available for download from the download page.

Silverlight for Windows Phone Toolkit

Also announced today was the release of the Silverlight for Windows Phone Toolkit (yes, that name is certainly a mouthful.) The toolkit release includes several additional controls for the phone, including a ContextMenu, Date & Time Pickers, a ToggleSwitch (think on/off light-switch), and a Wrap Panel. The toolkit also includes the Gesture Listener, which allows some common touch-based gestures to be easily hookup to event handlers right in the phone page’s Xaml markup. The Silverlight for Windows Phone Toolkit can be downloaded here, and general Silverlight Toolkit information can be found here. As with the other Silverlight Toolkits, the Source Code is available for download, as is a Sample Application. While the phone’s version of the sample browser is maybe not as slick as the “regular” Silverlight Toolkit’s (including source code visible directly in the application), it is still a great help. The Sources and Sample code can be found here.

More Free Jump-Start Webinars

In July, a series of Jump-Start webinars were produced which have been posted to Channel 9 as 12 hours’ worth of videos. Also announced today is an additional webinar series which will offer a deeper look at Windows Phone 7 development, including using the new Panorama, Pivot, and Map controls, Application Performance, Blend, and a live Q&A. The live webinar will span 7 hours on Tuesday, September 21 2010, and registration is available here. The original content is posted at Channel 9 here, with this content hopefully soon to follow.

Vermont Code Camp 2010 Presentation Materials

Julie Lerman and her team have once again put on a terrific event at the 2010 Vermont Code Camp. The host team’s terrific hospitality as well as the great facilities provided by the University of Vermont made this an extremely enjoyable event to attend and present at.

I have uploaded the content from my talk – Introduction to Windows Phone 7 Development with Silverlight – and the content can be found here (Slideshare link here). The uploaded content includes:

  • Presentation slides, which include the reference links I mentioned during the talk
  • An interactive pdf of the outline I prepared for the talk (Acrobat Reader may be required)
  • The sample application, with notes added to locate the key concepts that were discussed

The demo code was prepared with the Beta version of the Windows Phone Developer Tools – there may be breaking changes as later versions come out.