[Code] Saving an Image as Transient Data

If you’ve been developing Windows Phone 7 applications, you’re probably aware of tombstoning and information that should be handled during this process. An important factor is the storing of data to provide a seamless experience and give the illusion that the app has always been running. This data is commonly known as transient data and is essentially information that will not persist outside the app’s life cycle.  A useful example of transient data could be that of a user filling out a form and completing various textboxes. The app is then tombstoned and the user eventually returns to the app by pressing the ‘back’ button. By default, when the application is reloaded, the textboxes will be empty since a new instance is created. To provide the illusion that the same instance is running, and to improve the user experience, the app should refill all the data that had been entered prior to the tombstoning. That data should be stored in the PhoneApplicationPage.State property.

This property does have a limit of 2MB per page and 4mb for the whole application, so it’s best to store items only when needed. It is also important to remember that this property can only be accessed within the OnNavigatedTo and OnNavigatedFrom methods. To find out more on using the State property and storing transient data, you can read the tutorials on Application Life-Cycle found in the Windows Phone 7 Training Kit (RTM Refresh) and check out the MSDN ‘How to’ documentation. On a side note, the alternative to transient data is persistent data and is information that will be required between app life cycles such as user settings, saved game information, app data etc… For WP7 development, persistent data should be stored in the app’s Isolated Storage or on a remote server.

The problem

In an application I’m working on, I need to save an image as transient data. Seeing as the State property accepts type object as it’s value, I tried to directly pass the image stream to see what would happen. Turns out, when base.OnNavigatedFrom(e) got called, three exceptions were thrown:

A first chance exception of type 'System.Security.SecurityException' occurred in System.Runtime.Serialization.dll
A first chance exception of type 'System.Reflection.TargetInvocationException' occurred in mscorlib.dll
A first chance exception of type 'System.Security.SecurityException' occurred in System.Runtime.Serialization.dll

In release mode this resulted in the navigation stack becoming corrupted and therefore the user was unable to press the ‘back’ button to return to the app after it had been tombstoned. Drilling in a little deeper, it seemed that Visual Studio would catch this in the Application_UnhandledException event handler. The stacktrace provided by the exception object was:

at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.CreateDataContract(Int32 id, RuntimeTypeHandle typeHandle, Type type)
at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.GetDataContractSkipValidation(Int32 id, RuntimeTypeHandle typeHandle, Type type)
at System.Runtime.Serialization.DataContract.GetDataContractSkipValidation(Int32 id, RuntimeTypeHandle typeHandle, Type type)
at System.Runtime.Serialization.DataContract.GetDataContract(RuntimeTypeHandle typeHandle, Type type, SerializationMode mode)
at System.Runtime.Serialization.XmlObjectSerializerContext.GetDataContract(RuntimeTypeHandle typeHandle, Type type)
at System.Runtime.Serial

At the removal of the image stream, this exception was never thrown so it seems that there is a serialization problem when directly providing a stream.

A solution

If the Stream format was causing a problem, I thought a better way would to simply pass in a byte array. Bytes are serializable and easy to work with, so the following code demonstrates how to convert the image stream into a byte array.

//_imageStream is a variable that stores the stream (e.g. this might be obtained
//from the PhotoChooserTask's completed event parameter 'e.ChosenPhoto')
if (_imageStream != null)
//reset the stream position so it's at the beginning.
//this is important because any previous readings of the stream will ...
//position it at the end, causing an error when reading it.
 _imageStream.Position = 0;
      //Create a memorystream which is used to write to a byte array
     MemoryStream ms = new MemoryStream();
      //Create a byte array of the same length as the image stream
      byte[] buffer = new byte[_imageStream.Length];
      //read the imagestream into the byte array
      int read;
      while ((read = _imageStream.Read(buffer, 0, buffer.Length)) > 0)
            ms.Write(buffer, 0, read);
      //Save the image to the page's 'State' property
      if (State.ContainsKey("MyImage")) State.Remove("MyImage");
State.Add("MyImage", image);
The code above will convert your Stream to a Byte array and store the array into the page’s State. This needs to be done within the OnNavigatedFrom method since the State property is only accessible from here and OnNavigatedTo.

The final step, in the OnNavigatedTo method, is to convert the Byte array back into a stream and assign it to an image control.

//instantiate a new image and set it as the the previously stored stream
BitmapImage bmpImage = new BitmapImage();
//set the source of the BitmapImage to be the stream we saved earlier
bmpImage.SetSource(new MemoryStream(State["MyImage"] as Byte[]));
//update the image control to show the saved image
myImageControl.Source = bmpImage;

That should now display the image when the application is relaunched after being tombstoned. You should add more error checking code to make it more robust (e.g. ensure “MyImage” actually is a byte array), but the code above should hopefully get you started. If you have any comments or questions, feel free to post below.

Hope this helps!



3 Responses to [Code] Saving an Image as Transient Data

  1. Rene Schulte says:

    Please keep in mind that the Page’s State size is limited to 2 MB and you might encounter an exception if you want to save a large image.

    See the last paragraph here http://kodierer.blogspot.com/2010/09/windows-phone-memory-constraints.html

    • keyboardP says:

      Hi Rene,
      Yup, this is for use with smaller images rather than big ones and, as I say, it should only be used when needed.

  2. Pingback: Getting ready for Exam 70-599: Designing and Developing Windows Phone 7 Applications. Helpful Links and Resources | WP7 Developers Links

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: