In this tutorial article for Windows Phone 7 “Mango” Development we are touching on yet another important feature for developers to jump on board with; Fast App Switching. This feature is highly regarded as one of the easiest and better features to first implement in either old applications or ones you are starting from scratch. Essentially, the user is able to use your application, exit the application to do other important tasks and then hold the back button to traverse back to your application quickly. This is important for many developers as we do not want to get a “Resuming…” notification when we try and do this and Fast App Switching (FAS) is not enabled. To do this we only need one file of our application to be modified; App.xaml.cs. Jump below and look for what needs to be done to enable this useful feature.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using System.IO;
using System.IO.IsolatedStorage;
// Directives
using WP7LDBStorage.Model;
using WP7LDBStorage.ViewModel;
// Used For FAS
using System.Threading;
namespace WP7LDBStorage
{
public partial class App : Application
{
// Variables used in FAS
public static bool AppInitialized = false;
private static bool appInitialLoadPerformed = false;
// The Static ViewModel, to be used across our application.
private static ViewModelClass viewModel;
public static ViewModelClass ViewModel
{
get
{
return viewModel;
}
}
/// <summary>
/// Provides easy access to the root frame of the Phone Application.
/// </summary>
/// <returns>The root frame of the Phone Application.</returns>
public PhoneApplicationFrame RootFrame { get; private set; }
/// <summary>
/// Synchronization object used for safely updating the application data.
/// </summary>
public static object SyncObject { get; private set; }
/// <summary>
/// Gets whether or not the application was restored from tombstoning.
/// </summary>
public static bool WasTombstoned { get; private set; }

In the code above we are going to cover a couple different things starting with the using statements. The extra using statement we need to enable FAS is System.Threading; which is going to enable us to initialize our data and eliminate the “Resume…” message we get when trying to FAS on an application that does not support it. We can then jump just inside the public partial class App where we can see that we have initialized two boolean objects and they have both been set to false. The names of these two boolean objects are AppInitialized and AppInitialLoadPerformed. After we have instantiated them we can move down to two objects that are new to App.xaml.cs and these two new objects are SyncObject and WasTombstoned. SyncObject will give us a syncronization object that will be used to update the applications data. WasTombstoned is used to retreive information on whether the application was restored from a tombstoned state. These getter and setter calls are vital for the methods below to run.

/// <summary>
/// Constructor for the Application object.
/// </summary>
public App()
{
// Global handler for uncaught exceptions.
UnhandledException += Application_UnhandledException;
// Standard Silverlight initialization
InitializeComponent();
// Phone-specific initialization
InitializePhoneApplication();
// Show graphics profiling information while debugging.
if (System.Diagnostics.Debugger.IsAttached)
{
// Display the current frame rate counters.
Application.Current.Host.Settings.EnableFrameRateCounter = false;
// Show the areas of the app that are being redrawn in each frame.
//Application.Current.Host.Settings.EnableRedrawRegions = true;
// Enable non-production analysis visualization mode,
// which shows areas of a page that are handed off to GPU with a colored overlay.
//Application.Current.Host.Settings.EnableCacheVisualization = true;
// Disable the application idle detection by setting the UserIdleDetectionMode property of the
// application's PhoneApplicationService object to Disabled.
// Caution:- Use this under debug mode only. Application that disables user idle detection will continue to run
// and consume battery power when the user is not using the phone.
PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Disabled;
}
// Specify the local database connection string
string DBConnectionString = "Data Source=isostore:/Clients.sdf";
// Create the database if it does not exist
using (DataContextClass db = new DataContextClass(DBConnectionString))
{
if(db.DatabaseExists() == false)
{
// Create the local database
db.CreateDatabase();
db.SubmitChanges();
}
}
// Create the ViewModel Object
viewModel = new ViewModelClass(DBConnectionString);
// Query the local database and load observable collections
viewModel.LoadCollectionsFromDatabase();
}
// Code to execute when the application is launching (eg, from Start)
// This code will not execute when the application is reactivated
private void Application_Launching(object sender, LaunchingEventArgs e)
{
IsolatedStorageFile directory = IsolatedStorageFile.GetUserStoreForApplication();
if (!directory.FileExists("settings.txt"))
{
using (var myFilestream = new IsolatedStorageFileStream("settings.txt", FileMode.Create, IsolatedStorageFile.GetUserStoreForApplication()));
}
}
// Code to execute when the application is activated (brought to foreground)
// This code will not execute when the application is first launched
private void Application_Activated(object sender, ActivatedEventArgs e)
{
// Ensure that application state is restored appropriately
if (!e.IsApplicationInstancePreserved)
{
WasTombstoned = true;
App.AppInitialized = true;
Thread initialDataLoad = new Thread(new ThreadStart(InitializeData));
initialDataLoad.Start();
}
else
{
WasTombstoned = false;
}
}

This whole codeblock above was generated for us when we created our project. All of it except for the last method we have here, which is Application_Activated. Sure the method was generated for us but we are the ones creating the code inside it. Let us look inside Application_Activated to see what we will need in order to use FAS. We first want to make sure that the Applications instance is stable and intact which can be accomplished using our ActivatedEventArgs object in the method call named e. We then call e and its function IsApplicationInstancePreserved. If it returns false we want to change WasTombstoned and App.AppInitialized both to true. We then want to create a Thread object (initialDataLoad) that will run the InitializeData function when the thread is active. We can then go ahead and implement the thread in our code using the Start function of the object. If the applications state was preserved then we are going to make sure that WasTombstoned is kept false and exit our conditional statement.

// Code to execute when the application is deactivated (sent to background)
// This code will not execute when the application is closing
private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
}
// Code to execute when the application is closing (eg, user hit Back)
// This code will not execute when the application is deactivated
private void Application_Closing(object sender, ClosingEventArgs e)
{
}
// Code to execute if a navigation fails
private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e)
{
if (System.Diagnostics.Debugger.IsAttached)
{
// A navigation has failed; break into the debugger
System.Diagnostics.Debugger.Break();
}
}
// Code to execute on Unhandled Exceptions
private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
{
if (System.Diagnostics.Debugger.IsAttached)
{
// An unhandled exception has occurred; break into the debugger
System.Diagnostics.Debugger.Break();
}
}
#region Phone application initialization
// Avoid double-initialization
private bool phoneApplicationInitialized = false;
// Do not add any additional code to this method
private void InitializePhoneApplication()
{
if (phoneApplicationInitialized)
return;
// Create the frame but don't set it as RootVisual yet; this allows the splash
// screen to remain active until the application is ready to render.
RootFrame = new PhoneApplicationFrame();
RootFrame.Navigated += CompleteInitializePhoneApplication;
// Handle navigation failures
RootFrame.NavigationFailed += RootFrame_NavigationFailed;
// Ensure we don't initialize again
phoneApplicationInitialized = true;
}
private void InitializeData()
{
// Synchronize the data loading procedure
lock (SyncObject)
{
App.appInitialLoadPerformed = true;
if (null != InitialDataLoaded)
{
InitialDataLoaded(this, new EventArgs());
}
}
}
// Data initialization events
public event EventHandler<EventArgs> InitialDataLoaded;
// Do not add any additional code to this method
private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e)
{
// Set the root visual to allow the application to render
if (RootVisual != RootFrame)
RootVisual = RootFrame;
// Remove this handler since it is no longer needed
RootFrame.Navigated -= CompleteInitializePhoneApplication;
}
#endregion
}
}

Most of the above code is auto generated as well, minus two key items. This first is a method that we called earlier named InitializeData. We first want to start by locking our SyncObject which means that this is a critical section and we obtain a mutal-exclusion lock for this object. We will execute the code within the lock and then release the lock. Within the lock we are going to make appInitialLoadPerformed equal to true. We then want to check to see that our event handler InitialDataLoaded is not null and if it isn’t, we can then initialize a new event handler of InitialDataLoaded. After this is complete we release the lock and the method is complete.

With the last part of the code complete we have now implemented fast application switching. This will allow users to implement an important part of the “Mango” SDK and let the users benefit from it. You should now be able to implement fast application switching in your own application. If you have any trouble, questions, or comments, feel free to leave us a response in the comments section below. Until the next Mango development tutorial, Happy Hacking!

Share This
%d bloggers like this: