다음을 통해 공유


Tombstone territory: Preparing the App.XAML.CS for Tombstoning

If you looked at the code for the sdkExcecutionModelCS uses a View Model.  The code sample does a nice job of using the View Model.  By that I mean that usually the View Model samples are complex and hard to understand without lots of writing.

To keep the post shorter, in this blog I am only covering the App.XAML.CS code, the sample code is included for the entire app and follows the code in the sample: Tombstoning Sample . As a result I have not written about the presentation layer..

In this case, let’s use the example of storing a game score.  With the assistance of Kenny Spade, I was able to talk him into writing most of the code for me, as I am pretty weak at Linq/XDocument (so make sure you follow Kenny Space: Ace WhipperSnapper).

For the example, we will simply enter a value in a textbox and then use the process of tombstoning to maintain the value of the textbox when the app is put into one of the tombstone processes.  And if you look at my previous blog where I showed you a diagram that shows you the cycle of activation and deactivation in the Windows Phone, “Tombstoning in Windows 7”.

Creating the textbox and entering information isn’t the hard thing, but what happens if the end user gets a phone call?  The page disappears and the phone page appears, or what if they hit a “Toast”?  And so forth.

This example has a bunch of code to just make sure you store one textbox.  Not to worry, it is easily extended, and the extensions are normally the ones shown in the various examples that I cannibalized (mainly:  Tombstoning Sample, which extends the sample I generated from the code in that example):

Add code to the App.XAML.cs class, in this class (thanks Kenny!) the activation/deactivation happens for the XAML class is where you put code to control the information storage. (Code is attached to the BOTTOM of this blog, download the code, “Unblock” the code before unzipping, unzip the code and then open the solution to see all of the code shown here):

First, open a New Project-SilverlightPhone Application, add a textbox (not TEXTBLOCK), do not add any other presentation controls, just to keep everything simple.

Second, in the App.XAML.cs , I add a define statement at the very top so that I can use a precompile statement to test for debugging or release, and I am showing only the “using” statements that the code uses:

#define DEBUG  //Added for example
using System;  //defuault
using System.Windows; //default
using System.Windows.Navigation; //default
using Microsoft.Phone.Controls;  //default
using Microsoft.Phone.Shell; //default
using System.IO.IsolatedStorage; //added for example
using System.IO; //added for example

Now you will need to add the code to the App.XAML.CS, in the Class Variable area, add the following, this simple data structure would likely be too simple for use in the real world, but in our case it is very simple:

        public string AppDataObject {get; set;}

First off, why the {get; set;} nomenclature?  Oh, I hate to do this to you, but the best explanation ever is in the C# language specification: 10.7.3 Automatically implemented properties .  Basically when you use the format for a field like public var thingie {get; set;} two things happen if you use this format: You seem really cool and you are also setting up to use JIT automatic properties which makes your code just a little better.  What happens if you don’t use this format? Not much, but you do lose the cool factor, only a little though.  Go to the C# Language specifications and read about it.  All of the other explanations are confusing, overly complex and so forth.  Keep in mind this example: If you read a good translation of Plato directly, it makes sense, if you read someone’s interpretation, then Plato doesn’t make sense, for instance in college I usually used “Cliff” notes to jam through the “GE” courses.  Lately I have been going through the books and reading them directly, they make a lot of sense and are nice reads.  Same way with the C# Language Specifications, going direct sometimes overcomes confusion caused by complexity of samples.

 

In the method: Application_Activated:

The if statement was added to the existing method to test to see if the application is activated and if there is state data in the dictionary, if there is then assign it to the AppDataObject.  You could have a bunch of these statement, collections, etc. that you put into the dictionary.

Code Snippet

  1. private void Application_Activated(object sender, ActivatedEventArgs e)
  2.         {
  3.             // Check to see if the key for the application state data is in the State dictionary.
  4.             if (PhoneApplicationService.Current.State.ContainsKey("dataObject"))
  5.             {
  6.                 // If it exists, assign the data to the application member variable.
  7.                 AppDataObject = PhoneApplicationService.Current.State["dataObject"] as string;
  8.             }
  9.         }

 

Application_Deactivated

Make sure that the AppDataObject hasn’t been deleted or if it is empty, if there is information in the AppDataObject, put it into IsolatedStorage using the filename “myDataFile.txt”, you could use another file name, but in this case use the txt extension. 

The PhoneApplicationServices.Current.State:

  • Gets the dictionary used for passing an application’s state between invocations, in this case the dictionary is “dataObject”)

SaveDataToIsolatedStorage is a method that I copied from my source: Tombstoning Sample, and shown later.

Deactivated occurs when the app is sent to the background, for example when a call occurs.

Code Snippet

  1. private void Application_Deactivated(object sender, DeactivatedEventArgs e)
  2.         {
  3.             // If there is data in the application member variable...
  4.             if (!string.IsNullOrEmpty(AppDataObject))
  5.             {
  6.                 // Store it in the State dictionary.
  7.                 PhoneApplicationService.Current.State["dataObject"] = AppDataObject;
  8.  
  9.                 // Also store it in Isolated Storage, in case the application is never reactivated.
  10.                 SaveDataToIsolatedStorage("myDataFile.txt", AppDataObject);
  11.             }
  12.         }

Application_Closing

Closing occurs when the back button is pressed

Code Snippet

  1. // Code to execute when the application is closing (eg, user hit Back)
  2. // This code will not execute when the application is deactivated
  3. private void Application_Closing(object sender, ClosingEventArgs e)
  4. {
  5.     // The application will not be tombstoned, so only save to Isolated Storage
  6.     if (!string.IsNullOrEmpty(AppDataObject))
  7.     {
  8.         SaveDataToIsolatedStorage("myDataFile.txt", AppDataObject);
  9.     }
  10. }

Custom method added: SaveDataToIsolatedStorage

 

Code Snippet

  1. private void SaveDataToIsolatedStorage(string isoFileName, string value)
  2.  {
  3.      IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication();
  4.      StreamWriter sw = new StreamWriter(isoStore.OpenFile(isoFileName, FileMode.OpenOrCreate));
  5.      sw.Write(value);
  6.      sw.Close();
  7.      IsolatedStorageSettings.ApplicationSettings["DataLastSave"] = DateTime.Now;
  8.  }

Conclusions:

In this blog the process of using IsolatedStorage with the concept of Tombstoning to save the input in a textbox when a phone call or the user navigates off the page. In the next blog post, I will finish up the discussion with the code in the MainPage to capture the information stored in IsolatedStorage. It may seem somewhat complex but it worth it to make your apps more professional. 

TombstoneSimple.zip