Mar 7 2011

Serializing the Unserializable

Category: MobileJoel Ivory Johnson @ 13:33

I came across a post in the Windows Phone developer forums that got me thinking for a moment. The poster had asked how to serialize a class that was not serializable. The class of interest was the StrokeCollection class. The solution for this problem has actually been around for a while but under different terms. If you pick up a design patterns book and look up Data Transfer Object (DTO) you'll see what I'm talking about. For the sake of those that don't have a design patterns book handy I'll describe the concept.

A DTO exists for the sake of storing data in an object that is suitable for crossing boundaries. More times than not when I see some one talking about a DTO it is for an object that is going from an application to a database. But it's not restricted to that scenario. For the sake of answering the question for the poster I can assume that he or she wanted to transfer the data to a file. The representation of the data in a file is also a form that is suitable for transfer over a wire.

To accomplish the task I made a few classes that have some (but not all) of the same properties as the classes I needed to serialize. I didn't need to replicate all of the properties because I'm not interested in saving all of the data that the class provides. As far as functionality goes the only thing that I've put on these classes is functions for converting from the DTO to the original class and vice versa. The StrokeCollection class uses a number of other classes to represent it's data. StrokeCollection caontains instances of Stroke, which contains instances of StylusPointCollection, and that contains instances of StylusPoint. I created a similar hierarchy with the members of that hierarchy marked as serializable (with the [DataContract] attribute). For saving and loading the data I've made use of the serialization code from a previous post.

    [DataContract]
    public class StrokeDto
    {

        public StrokeDto()
        {
        }

        public StrokeDto(Stroke source)
        {
            this.StylusPointDtos = new StylusPointDtoCollection(source.StylusPoints);
        }

        public Stroke ToStroke()
        {
            Stroke retVal = new Stroke();
            if(this.StylusPointDtos!=null)
                StylusPointDtos.ForEach((o)=>retVal.StylusPoints.Add(o.ToStylusPoint()));
            return retVal;
        }

        [DataMember]
        public StylusPointDtoCollection StylusPointDtos { get; set; }
    }

    public class StrokeDtoCollection: List
    {
        public StrokeDtoCollection()
        {
        }

        public StrokeDtoCollection(StrokeCollection source):this()
        {
            foreach(Stroke s in source)
            {
                this.Add(new StrokeDto(s));
            }
        }

        public StrokeCollection ToStrokeCollection()
        {
            StrokeCollection retVal = new StrokeCollection();
            this.ForEach((o)=>retVal.Add(o.ToStroke()));
            return retVal;
        }
    }

    [DataContract]
    public class StylusPointDto
    {

        [DataMember]
        public double X { get; set;  }

        [DataMember]
        public double Y { get; set;  }

        [DataMember]
        public float PressureFactor { get; set;  }

        public StylusPointDto()
        {}

        public StylusPointDto(StylusPoint source)
        {
            this.X = source.X;
            this.Y = source.Y;
            this.PressureFactor = source.PressureFactor;
        }

        public StylusPoint ToStylusPoint()
        {
            return new StylusPoint(this.X, this.Y) {PressureFactor = this.PressureFactor};
        }
    }
    public class StylusPointDtoCollection : List
    {

        public StylusPointDtoCollection(): base()
        {}

        public StylusPointDtoCollection(StylusPointCollection source): this()
        {
            var sourceList = (from point in source select new StylusPointDto(point)).ToArray();
            this.AddRange(sourceList);
        }

        public StylusPointCollection ToStylusPointCollection()
        {
            var retVal = new StylusPointCollection();
            this.ForEach((o) => retVal.Add(o.ToStylusPoint()));
            return retVal;
        }
    }

With my class hierarchy and the serialization code I was able to load and save the stokes in a few lines of code. 

 

//Save the Strokes
var valuesaveDto = new StrokeDtoCollection(myInkPresenter.Strokes);
_myInkSaver.SaveMyData(valuesaveDto,"MyInk.ink");


//Load the Strokes
var valueDto = _myInkSaver.LoadMyData("MyInk.ink");
myInkPresenter.Strokes = valueDto.ToStrokeCollection();


Screen Shot of Drawing Program

I've put together an example program (see link at top of article) that uses the code. Word of warning, I've not implemented any tombstoning code in it. But draw what eer you like and then click on the Save button. After you exit from the program when you go back into it you'll see your picture reload.

 

Tags: ,