About a year ago I shared a simple utility class for saving serializable data on Windows Phone 7. I just updated the component for Windows 8 Metro. It still retains compatibility with Windows Phone 7 through the use of conditional compiler directives. On Windows Phone 7 I've changed the class so that it is static (so no need to instantiate it).
For Metro the methods are asynchronous. For saving an action can be passed that will be called once the save operation is complete. When loading data you'll want to pass an action that will received the loaded data and an exception parameter that will be populated if the data could not be loaded.
As an example of how the code works (and the platform dependent differences in its usage) here is a method from a program I have that is using the code. The program compiles on both Windows Phone 7 and Windows Metro.
public void LoadAccess()
{
#if SILVERLIGHT
AccessInfo = DataSaver<AccessInfo>.LoadMyData("_accessToken.xml");
#endif
#if NETFX_CORE
DataSaver<AccessInfo>.LoadDataAsync("_accessToken.xml", (info, exc)=>
{
if (info != null)
{
this.AccessInfo = info;
}
});
#endif
}
public void SaveAccessToken()
{
if (this.AccessInfo != null)
{
#if NETFX_CORE
DataSaver<AccessInfo>.SaveMyDataAsync(this.AccessInfo, "_accessToken.xml");
#endif
#if SILVERLIGHT
DataSaver<AccessInfo>.SaveMyData(AccessInfo, "_accessToken.xml");
#endif
}
}
If you've never seen the #if/#endif directives before it is used to essentially conditionally comment out sections of code based on some condition. In this case the condition is certain compiler constants being defined. Some constants are automatically created for various project types. If you create a Windows Phone project the WINDOWS_PHONE
and SILVERLIGHT
constants are defined. For a Windows 8 Metro project the NETFX_CORE
constant is defined. When you are viewing the code in the Visual Studio IDE, it will gray out any code that is going to be ignored because of the conditional compilation statements.
Below is the code for the serializer:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.IO;
#if SILVERLIGHT
using System.IO.IsolatedStorage;
#endif
#if NETFX_CORE
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.Streams;
#endif
namespace J2i.Net.Utility
{
public class DataSaver<MyDataType>
{
static List<Type> _knownTypeList = new List<Type>();
public static List KnownTypeList
{
get
{
return _knownTypeList;
}
}
#if SILVERLIGHT
private static IsolatedStorageFile _isoFile;
static IsolatedStorageFile IsoFile
{
get
{
if (_isoFile == null)
_isoFile = System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication();
return _isoFile;
}
}
public static void SaveMyData(MyDataType sourceData, String targetFileName)
{
try
{
using (var targetFile = IsoFile.CreateFile(targetFileName))
{
var d = new DataContractSerializer(typeof(MyDataType), KnownTypeList);
d.WriteObject(targetFile, sourceData);
}
}
catch (Exception )
{
IsoFile.DeleteFile(targetFileName);
}
}
public static MyDataType LoadMyData(string sourceName)
{
MyDataType retVal = default(MyDataType);
if (IsoFile.FileExists(sourceName))
using (var sourceStream = IsoFile.OpenFile(sourceName, FileMode.Open))
{
var d = new DataContractSerializer(typeof(MyDataType), KnownTypeList);
retVal = (MyDataType)d.ReadObject(sourceStream);
}
return retVal;
}
#endif
public DataSaver()
{
}
#if NETFX_CORE
public static async void SaveMyDataAsync(
MyDataType sourceData,
String targetFileName,
Action<MyDataType,String, Exception> OnSaved = null)
{
try
{
StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync(
targetFileName, CreationCollisionOption.ReplaceExisting
);
IRandomAccessStream raStream = await file.OpenAsync(FileAccessMode.ReadWrite);
IOutputStream outStream = raStream.GetOutputStreamAt(0);
DataContractSerializer serializer = new DataContractSerializer(typeof(MyDataType), KnownTypeList);
serializer.WriteObject(outStream.AsStreamForWrite(), sourceData);
await outStream.FlushAsync();
if(OnSaved!=null)
OnSaved(sourceData, targetFileName, null);
}
catch (Exception exc)
{
if (OnSaved != null)
{
OnSaved(sourceData, targetFileName, exc);
}
}
}
public static async void LoadDataAsync(string fileName,
Action<MyDataType, Exception> loadAction)
{
if (loadAction == null)
return;
try
{
StorageFile file = await ApplicationData.Current.LocalFolder.GetFileAsync(fileName);
if (file == null) return;
IInputStream inStream = await file.OpenSequentialReadAsync();
DataContractSerializer serializer =
new DataContractSerializer(typeof(MyDataType), KnownTypeList);
MyDataType data = (MyDataType)serializer.ReadObject(inStream.AsStreamForRead());
loadAction(data, null);
}
catch (Exception e)
{
loadAction(default(MyDataType), e);
}
}
#endif
}
}