次の方法で共有


Windows Phone 7 XML IsolatedStorage Example

For one of the apps I have been working on, I needed to persist a List<T> of T objects across sessions. They are simple objects with simple properties, so I decided to use XML. However, since WP7 is a new platform, there’s not a lot of information out there on what is a good best practice.

It turns out for simple situations like mine, serializing objects into XML and writing that to file is by far the easiest way to do it.

Let’s examine a scenario.

The App

This is not an app I am working on, but it is basically the same thing.

Let’s say that you want to track your jogs. Starting simple, you decide to track the following properties:

  • RouteID : int
  • Duration : TimeSpan (we will encounter an interesting serialization bug with TimeSpan as well)
  • Date : DateTime
  • Distance (miles) : float

Of course, we won’t attempt to build all of this here, but rather, focus on the storage aspect of it.

The “Jog” Object

You will persist a list of these objects to be able to view them historically. This is what a Jog object might look like. Note the extra property, DurationXml, with its special attributes – this exists because XmlSerializer does not properly serialize TimeSpan objects.

     public class Jog
    {
        private TimeSpan _duration = new TimeSpan();
        public DateTime Date { get; set; }
        [XmlIgnore]
        public TimeSpan Duration
        {
            get { return _duration; }
            set { _duration = value; }
        }
        // HACK: This property only exists for XML serialization.
        // It gets serialized as a <Duration> tag.
        [XmlElement("Duration", DataType="duration")]
        public string DurationXml
        {
            get
            {
                return XmlConvert.ToString(_duration);
            }
            set
            {
                if (value == null)
                {
                    _duration = TimeSpan.Zero;
                    return;
                }
                TimeSpan newDuration = XmlConvert.ToTimeSpan(value);
                if (_duration == newDuration)
                    return;
                _duration = newDuration;
            }
        }
        public int RouteID { get; set; }
        public float Distance { get; set; }
    }

Note the hackery around the Duration and DurationXml properties.

Jog List

For the purposes of this app, you’d have a List of Jog objects: List<Jog> which you keep as a static on the App class and maintain it there. You’d then create some methods in the App class that would help out with storage, and then call them from Application_Closing, Application_Launching, and Activated/Deactivated as you handle tombstoning and deactivation.

Storage Helper

Then, you might write a class like this which helps with storage, and keep it statically on the App class. All you have to do is call XmlSerializer.Serialize(object) and XmlHelper.Deserialize(xml) to manage the saving/loading of your object list. Put together, it looks like this:

     public class StorageHelper
    {
        private const string FILE_NAME = "Jogs.xml";
        public List<Jog> LoadJogs()
        {
            List<Jog> jogs = new List<Jog>();
            TextReader reader = null;
            try
            {
                IsolatedStorageFile isoStorage = IsolatedStorageFile.GetUserStoreForApplication();
                IsolatedStorageFileStream file = isoStorage.OpenFile(FILE_NAME, FileMode.OpenOrCreate);
                reader = new StreamReader(file);
 
                XmlSerializer xs = new XmlSerializer(typeof(List<Jog>));
                jogs.AddRange((List<Jog>)xs.Deserialize(reader));
                reader.Close();                
            }
            catch
            {
                
            }
            finally
            {
                if (reader != null)
                    reader.Dispose();                
            }
            return jogs;
        }
        public void SaveJogs(List<Jog> jogs)
        {
            TextWriter writer = null;
            try
            {
                IsolatedStorageFile isoStorage = IsolatedStorageFile.GetUserStoreForApplication();
                IsolatedStorageFileStream file = isoStorage.OpenFile(FILE_NAME, FileMode.Create);
                writer = new StreamWriter(file);
                XmlSerializer xs = new XmlSerializer(typeof(List<Jog>));
                xs.Serialize(writer, jogs);
                writer.Close();
            }
            catch
            {
            }
            finally
            {
                if (writer != null)
                    writer.Dispose();
            }
        }
        public StorageHelper()
        {
        }
    }

Don’t Forget Your References

One thing to note here is that several of the Xml classes won’t magically work with IntelliSense. You need to add references to System.Xml and System.Xml.Serialization for all this good stuff to work.

I’ll be posting an example Jog Tracker application that uses isolated storage in the coming weeks, but for now, this should be enough to get you started.

Comments

  • Anonymous
    August 31, 2010
    Excellent posting!  I am writing a series on using UML in Visual Studio 2010 Ultimate at: http://bit.ly/alMGtu

  • Anonymous
    August 31, 2010
    Excellent posting!  I am writing a series on using UML in Visual Studio 2010 Ultimate at: http://bit.ly/alMGtu

  • Anonymous
    November 06, 2010
    Nice post. I'd only suggest to use using statements for IsolatedStorageFile and IsolatedStorageFileStream as they implement IDisposable.

  • Anonymous
    December 29, 2010
    This seems to directly contridict the MSDN documentation for win7 phone. msdn.microsoft.com/.../system.xml.serialization.xmlserializer(v=VS.95).aspx It states you can't use xmlserializer on an ArrayList or List<T>.

  • Anonymous
    December 29, 2010
    This seems to directly contridict the MSDN documentation for win7 phone. msdn.microsoft.com/.../system.xml.serialization.xmlserializer(v=VS.95).aspx It states you can't use xmlserializer on an ArrayList or List<T>.

  • Anonymous
    December 29, 2010
    Hey Jason, The documentation states that it can't serialize arrays of ArrayList or arrays of List<T>. This means you can't serialize arrays where every element is another array. This example only deals with one-dimensional arrays.

  • Anonymous
    February 22, 2011
    You mentioned you would be posting an example Jog Tracker application, I was just wondering if you ever got round to it?

  • Anonymous
    March 02, 2011
    orale k padre x sierto saves como guardar y leer informacion  de un txt en windows phone game 4.0????

  • Anonymous
    March 02, 2011
    @alf: Puede guardar cualquier tipo de datos en almacenamiento aislado. No debe estar en formato XML. Sin embargo, esto es la forma más fácil de hacerlo. Mis disculpas por gramática incorrecta; Esto viene de una herramienta de traductor.