Hands-On Lab
Windows Phone Application Life Cycle—Tombstoning
Lab version:1.0.0
Last updated:10/27/2018
Contents
Overview
Exercises
Exercise 1: Introducing the Windows Phone Application Life Cycle—Tombstoning
Task 1 – Connecting the Application to Existing Data
Task 2 – Application Execution Model: Handling application and page navigation events
Summary
Overview
The Windows Phone execution model governs the life cycle of applications running on a Windows Phone, from when the application is launched until it is terminated. The execution model is designed to provide end users with a fast, responsive experience at all times. To achieve this, Windows Phone allows only one application at a time to run in the foreground—the visible application with which the user interacts. This eliminates the possibility of users getting their devices into a state where multiple applications are running in the background competing over the same limited resources, resulting in sluggish performance and excessive battery draw-down.
The Windows Phone execution model maintains a journal of the applications and pages viewed by the user. This defines the path of the phone’s Back key, which gives the user the option to navigate back through different applications and pages. This is useful when an application accesses the web or other phone service, as the user can at any point simply tap Back to return to the previous experience.
As noted above, only a single application can run in the foreground and no third-party applications are allowed to run in the background. Therefore when the user navigates away from your application, either to a chooser like picture chooser or to a launcher like phone call, the Windows Phoneoperating systemsuspends your application for a limited time. If resources are required by the operating system, your application might even get terminated.
The procedure in which the operating system suspends an application’s process when the user navigates away from the applicationis called tombstoning. The operating system maintains state information about the application. If the user navigates back to the application, the operating system resumes the application process (or restartsit if it was terminated before) and passes the state data back to the application, where the user will be able to continue seamlessly from his last interaction point with the application.
This lab focuses on thetombstone(or tombstoning) aspect of the Windows Phone Application life cycle and its effects.
Objectives
At the end of the lab you will:
- Be familiar with the tombstoning aspect of the Windows Phone 7 application lifecycle
- Understand how application launching, activation, deactivation, and closing events work
- Create a simple Silverlight application that uses these techniques to save an application’s state while navigating away from the application and restore it upon returning to the application
Prerequisites
The following is required to complete this hands-on lab:
- Microsoft Visual Studio 2010 Express for Windows Phone or Microsoft Visual Studio 2010
- Windows Phone Developer Tools
Note: All of these Tools can be downloaded together in a single package from
Setup
For convenience, much of the code used in this hands-on lab is available as Visual Studio code snippets. To check the prerequisites of the lab and install the code snippets:
- Run the SetupLab.cmd script located in the lab's Source\Setup folder to check dependencies and install any missing prerequisites.
- Once you have verified every prerequisite, follow the instructions to install the code snippets.
Using the Code Snippets
With code snippets, you have all the code you need at your fingertips. The lab document will tell you exactly when you can use them. For example,
Figure 1
Using Visual Studio code snippets to insert code into your project
To add this code snippet in Visual Studio, you simply place the cursor where you would like the code to be inserted, start typing the snippet name (without spaces or hyphens), watch as IntelliSense picks up the snippet name, and then press the Tab key twice when the snippet you want is selected. The code will be inserted at the cursor location.
Figure 2
Start typing the snippet name
Figure 3
Press Tab to select the highlighted snippet
Figure 4
Press Tab again to expand the snippet
To insert a code snippet using the mouse rather than the keyboard, right-click where you want to insert the code snippet, select Insert Snippet followed by My Code Snippets, and then pick the relevant snippet from the list.
To learn more about Visual Studio IntelliSense Code Snippets, including how to create your own, see
Exercises
This hands-on lab comprises the following exercise:
- Introduction to the Windows Phone Application Life Cycle—Tombstoning
Estimated time to complete this lab: 45 minutes.
Exercise 1: Introducing the Windows Phone Application Life Cycle—Tombstoning
This exercise uses a provided starter solution for Microsoft Visual Studio 2010 Express for Windows Phone or Microsoft Visual Studio 2010. This solution includes a simple Windows Phone 7 application that creates and displays travel reports. The following tasks illustrate how tombstoning works are completed:
- Connect the application to existing data and add calls to log
- Handle application and page navigation events
We will use the Visual Phone Developer 2010 Express development environment, and will deploy to the Windows Phone Emulatorfor debugging. The solution we will work with is based upon the Silverlight for Windows Phone Application template. During development, we will add a Silverlight for Windows Phone project-specific item, the Windows Phone Portrait Page.
Note: The steps in this hands-on lab illustrate procedures using Microsoft Visual Studio 2010 with theWindows Phone Developer Tools, but they are equally applicable to Microsoft Visual Studio 2010 Express for Windows Phone. Instructions that refer generically to Visual Studio apply to both products.
Task 1 – Connectingthe Application to Existing Data
This taskuses aprovided starter solution for Microsoft Visual Studio 2010 Express for Windows Phone or Microsoft Visual Studio 2010. The solution includes the sample Windows Phone 7 application with 3 pages and some preparations for later tasks in this Lab.
- OpenMicrosoft Visual Phone Developer 2010 Express from Start | All Programs | Microsoft Visual Studio 2010 Express.
Visual Studio 2010: Open Visual Studio 2010 from Start | All Programs | Microsoft Visual Studio 2010.
- From the Menu Bar, select File. The File sub-menu is displayed.
- FromtheFilesub-menu,select Open Project. The Open Project window is displayed.
Visual Studio 2010: In the File sub-menu, point to open and select Project/Solution.
- Navigate to this lab’s starter project location in the Source\Ex1-Tombstoning\Begin folder, selectApplicationLifecycle.sln, and click Open.
Figure 5
Opening the starter solution
- Examine the opened project:
◦The project is a standard Windows Phone Application, with a customized MainPage.xaml, two pages that work as a wizard for editing trips, one page to display a saved trip, additional resources in App.xaml,and a changed SplashScreenImage.jpg.
- A few external tools are used:
◦A Logger class that assists in keeping track of the order in which functions are called.
◦A NonLinearNavigationService class thatassists in implementing a wizard behavior when navigating to different pages.
◦AUtils class that wraps the application serializing calls isolated storage.
- To add the Utils class, add a new project folder to the created project and name it Misc. To do this, right-click the project name (ApplicationLifecycle), select Add and then New Folder. Rename the new folder to Misc.
Figure 6
Creating a new project folder
- Add the providedUtils helper class from the {LAB_PATH}\Assets folder to the Misc folder. To do this, right-click theMisc folder, select Add and then Existing Item:
Figure 7
Adding assets to the project
Note: Alternatively, you could select the Misc folder and press the keyboard shortcut Shift + Alt + A.
- At the “Add Existing Item” dialog, navigate to the Lab Assets folder location, select the Utils.cs source file asset, and click Add:
Figure 8
Adding assets
- To include the Logger and the NonLinearNavigationService classes, a reference to their assemblies must be added to the project. Right click the References project folder and select Add Reference.
Figure 9
Adding a new referenced assembly
- In the Add Reference dialog choose the Browse tab and navigate to the {LAB_PATH}\Assets folder. Choose both assemblies that exist in this folder and click OK.
Figure 10
Choosing the referenced assemblies
- Add a reference to the System.Xml.Serialization assembly to the project references. Right click the References project folder and select Add Reference:
Figure 11
Adding a new referenced assembly
- In the Add Reference dialog choose the .NET tab, locate System.Xml.Serialization in the Component list and click OK:
Figure 12
Adding a reference
- Currently, the application does not persist its data. This means that if we run the application, modify its data and then restart the application, the modified data would not appear. The TripViewModel class holds the application data. This class saves the data to application's isolated storage. Open TripListViewModel.cs and locate the following comment:
C#
//TODO: Add a function to load trips from file
- Replace it with the following code snippet:
(Code Snippet – Application Lifecycle – Ex 1 Task 1 Step 15 – LoadTrips function)
C#
// Load trips from file and add them to the ObservableCollection
publicvoidLoadTrips()
{
Trips.Clear();
ListTravelReportInfo> trips =
Utils.LoadTravelReports("TravelReportInfo.dat");
foreach (TravelReportInfo trip in trips)
{
if (!trip.IsBeingEdited)
{
Trips.Add(trip);
}
else
{
CurrentTrip = trip;
}
}
}
- Find theSaveCurrentTrip function and locate the following comment:
C#
//TODO: Call the util class to save all the trips
- Replace it with the following code snippet:
(Code Snippet – Application Lifecycle – Ex 1 Task 1 Step 17 – SaveCurrentTripfunction)
C#
// Get trips from the ObservableCollection and save them to file
ListTravelReportInfo> trips = newListTravelReportInfo>(Trips);
// Save the current trip if it is still being edited
if (CurrentTrip.IsBeingEdited)
{
trips.Add(CurrentTrip);
}
Utils.SaveTravelReports(trips, "TravelReportInfo.dat", addToList);
- Open App.xaml.cs, find the InitViewModelfunction and locate the following comment:
C#
//TODO: Load data into tripListViewModel
- Replace it with the following code:
C#
tripListViewModel.LoadTrips();
- As mentioned earlier, updating the data in the application works in a wizard like flow – there are two pages, one following the other, that are responsible for updating the data. When the user finishes updating the second edit page, the wizard operation is completed and the application should navigate back to the main page where all the data is presented. The naïve way of implementing this behavior would be to navigate to the main page from the second edit page. Unfortunately this approach will create an unwanted behavior – if the user taps the back button after returning to the main page, the application will navigate back to the second edit page of the wizard. This is not what the user would expect of a wizard process. A better behavior would be to leave the application if the user taps the back button while the main page is displayed. To achieve this,we use the external NonLinearNavigationServiceasset class . This class follows the navigation process and when it discovers a "navigation loop" it simply causes the application to navigate backward, rather than forward, to the navigated page. To support this process, a few calls to the NonLinearNavigationService need to be made.
- Open App.xaml.cs andadd the following code snippet below the using statements at the beginning of the file:
C#
usingWindowsPhoneRecipes;
- Find the App class constructor and locate the following comment:
C#
//TODO: Initialize the NonLinearNavigationService
- Replace it with the following codesnippet:
(Code Snippet – Application Lifecycle – Ex 1 Task 1 Step 23 – App class ctor)
C#
// init the non linearnav service,
// make sure you call it last in the app CTOR
NonLinearNavigationService.Instance.Initialize(RootFrame);
- Open EditTripFirstPage.xaml.cs andadd the following code snippet below the using statements at the beginning of the file:
C#
usingWindowsPhoneRecipes;
- Find the OnNavigatedTo function and locate the following comment:
C#
//TODO: Handle recursive navigation
- Replace it with the following codesnippet:
(Code Snippet – Application Lifecycle – Ex 1 Task 1 Step 26 – OnNavigatedTofunction)
C#
// If we are in recursive back - DO NOT DO ANY WORK ON PAGE
// Developers - make sure you have no specific logic that you need
// to take care of here
if (NonLinearNavigationService.Instance.IsRecursiveBackNavigation == true)
{
return;
}
- Open EditTripSecondPage.xaml.cs andadd the following code snippets below the using statements at the beginning of the file:
C#
usingWindowsPhoneRecipes;
- Find the OnNavigatedTo function and locate the following comment:
C#
//TODO: Handle recursive navigation
- Replace it with the following code snippet:
(Code Snippet – Application Lifecycle – Ex 1 Task 1 Step 29 – OnNavigatedTofunction)
C#
// If we are in recursive back - DO NOT DO ANY WORK ON PAGE
// Developers - make sure you have no specific logic that you need
// to take care of here
if (NonLinearNavigationService.Instance.IsRecursiveBackNavigation == true)
{
return;
}
- This lab uses a Logger class to help analyze the different states the application enters. A call to the Logger class is required in key functions:
- Open App.xaml.cs, find theApplication_Launching function and locate the following comment:
C#
//TODO: Create log data
- Replace it with the following code:
C#
WindowsPhoneRecipes.Logger.Instance.AddLine();
- Repeat the previous 2 steps of creating log lines for the following functions under App.xaml.cs:
- Application_Activated
- Application_Deactivated
- Application_Closing
- App class constructor
- Open MainPage.xaml.cs, find the class constructor and locate the following comment:
C#
//TODO: Create log data
- Replace it with the following code:
C#
WindowsPhoneRecipes.Logger.Instance.AddLine();
- Repeat the previous 2 steps of creating log lines for the following function under MainPage.xaml.cs: OnNavigatedTo.
- Locate function ShowHideLogButton_Click and replace its comment with the following code snippet, which displays the log data:
(Code Snippet – Application Lifecycle – Ex 1 Task 1 Step 36 – ShowHideLogButton_Clickfunction)
C#
privatevoidShowHideLogButton_Click(object sender, EventArgs e)
{
// toggles the log area visibilty
if (svLog.Visibility == Visibility.Collapsed)
{
// get the updates log lines from the logger
txbLog.Text =
WindowsPhoneRecipes.Logger.Instance.Log.ToString();
svLog.Visibility = Visibility.Visible;
ContentPanel.Visibility = Visibility.Collapsed;
}
else
{
svLog.Visibility = Visibility.Collapsed;
ContentPanel.Visibility = Visibility.Visible;
}
}
- Open EditTripFirstPage.xaml.cs, find the class constructor, and locate the following comment:
C#
//TODO: Create log data
- Replace it with the following code:
C#
WindowsPhoneRecipes.Logger.Instance.AddLine();
- Repeat the previous 2 steps of creating log lines for the following functions under EditTripFirstPage.xaml.cs:
- OnNavigatedTo
- OnNavigatedFrom
- Locate the function ShowHideLogButton_Click and replace its comment with the following code snippet, which displays the log data:
(Code Snippet – Application Lifecycle – Ex 1 Task 1 Step 41 – ShowHideLogButton_Clickevent handler)
C#
privatevoidShowHideLogButton_Click(object sender, EventArgs e)
{
// toggles the log area visibilty
if (svLog.Visibility == Visibility.Collapsed)
{
// get the updates log lines from the logger
txbLog.Text =
WindowsPhoneRecipes.Logger.Instance.Log.ToString();
svLog.Visibility = Visibility.Visible;
ContentPanel.Visibility = Visibility.Collapsed;
}
else
{
svLog.Visibility = Visibility.Collapsed;
ContentPanel.Visibility = Visibility.Visible;
}
}
- Open EditTripSecondPage.xaml.cs, find the class constructor and locate the following comment:
C#
//TODO: Create log data
- Replace it with the following code:
C#
WindowsPhoneRecipes.Logger.Instance.AddLine();
- Repeat the previous 2 steps of creating log lines for the following functions under EditTripSecondPage.xaml.cs:
- OnNavigatedTo
- OnNavigatedFrom
- Locate the function ShowHideLogButton_Click and replace its comment with the following code snippet, which displays the log data:
(Code Snippet – Application Lifecycle – Ex 1 Task 1 Step 45 – ShowHideLogButton_Clickevent handler)
C#
privatevoidShowHideLogButton_Click(object sender, EventArgs e)
{
// toggles the log area visibilty
if (svLog.Visibility == Visibility.Collapsed)
{
// get the updates log lines from the logger
txbLog.Text =
WindowsPhoneRecipes.Logger.Instance.Log.ToString();
svLog.Visibility = Visibility.Visible;
ContentPanel.Visibility = Visibility.Collapsed;
}
else
{
svLog.Visibility = Visibility.Collapsed;
ContentPanel.Visibility = Visibility.Visible;
}
}
- Open ShowTripPage.xaml.cs, find the class constructor and locate the following comment:
C#
//TODO: Create log data
- Replace it with the following code:
C#
WindowsPhoneRecipes.Logger.Instance.AddLine();
- Repeat the previous 2 steps of creating log lines for the following function under ShowTripPage.xaml.cs:
- OnNavigatedTo
- Locate function ShowHideLogButton_Click and replace its comment with the following code snippet, which displays the log data:
(Code Snippet – Application Lifecycle – Ex 1 Task 1 Step 49 – ShowHideLogButton_Clickevent handler)
C#
privatevoidShowHideLogButton_Click(object sender, EventArgs e)
{
// toggles the log area visibilty
if (svLog.Visibility == Visibility.Collapsed)
{
// get the updates log lines from the logger
txbLog.Text =
WindowsPhoneRecipes.Logger.Instance.Log.ToString();
svLog.Visibility = Visibility.Visible;
ContentPanel.Visibility = Visibility.Collapsed;
}
else
{
svLog.Visibility = Visibility.Collapsed;
ContentPanel.Visibility = Visibility.Visible;
}
}
- Compile the application and fix errors, if any.
- Run the application.
- Observe the main page. Notice that 3 trips are included already; during startup the LoadTravelReports in the Utils class is called. If it finds a trips database file in the application's isolated storage, it loads the file.Otherwise, it copies a default database file that was packaged in the project (find it under Resources folder).