Over a million developers have joined DZone.

Saving an Image as Transient Data

DZone's Guide to

Saving an Image as Transient Data

Free Resource
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!


Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}