As stated in the title, I am attempting to serialize and deserialize the contents of a canvas within WPF. I have been using this link as my guide. In this case, the contents of the canvas are custom user controls that are added by the user. In my program , these are blue circles and red squares (used for simplicity and ease of explanation).
Currently, I can save and load a file, however, when loading the saved file, there are a few issues that arise.
The program does create the correct number of shapes though. However, quite unhelpfully, I am not sure whether serialisation, deserialisation or both is where the program is failing.
To aid understanding, here is the class that is storing the shapes, ready for serialisation:
[Serializable()]
public class shaypeh
{
private double x, y;
private bool circleOrSquare;
public shaypeh()
{
}
public shaypeh(double x, double y, bool circleOrSquare)
{
this.x = x;
this.y = y;
this.circleOrSquare = circleOrSquare;
}
public bool getCircleOrSquare()
{
return circleOrSquare;
}
public double getX()
{
return x;
}
public double getY()
{
return y;
}
}
The following code is the function that I am using to save the canvas. I suspect that this is the issue with the program, however I am unsure where I am going wrong.
Here is the output when 2 circles and 1 square are added to the canvas and then it is saved.
<?xml version="1.0"?>
<ArrayOfShaypeh xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<shaypeh />
<shaypeh />
<shaypeh />
</ArrayOfShaypeh>
double top;
double left;
List<shaypeh> shaypehs = new List<shaypeh>();
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "Text file (*.txt)|*.txt|XML (*.xml)|*.xml";
if (sfd.ShowDialog() != true)
{
return;
}
foreach(object obj in pictureBoard.Children)
{
if (obj is Circle)
{
UIElement s = (Circle)obj;
top = Canvas.GetTop(s);
left = Canvas.GetLeft(s);
shaypehs.Add(new shaypeh(left, top, true));
}
if (obj is Rectangle)
{
UIElement s = (Rectangle)obj;
top = Canvas.GetTop(s);
left = Canvas.GetLeft(s);
shaypehs.Add(new shaypeh(left, top, true));
}
}
XmlSerializer serializer = new XmlSerializer(typeof(List<shaypeh>));
using (FileStream stream = File.Create(sfd.FileName))
{
serializer.Serialize(stream, shaypehs);
}
The following code is what I am using to then deserialise the file. This I do believe is correct, however I am unsure about this.
OpenFileDialog ofd = new OpenFileDialog();
ofd.DefaultExt = ".xml";
ofd.Filter = "Text file (*.txt)|*.txt|XML (*.xml)|*.xml";
if (ofd.ShowDialog()!= true)
{
return;
}
pictureBoard.Children.Clear();
XmlSerializer serializer = new XmlSerializer (typeof(List<shaypeh>));
using (FileStream stream = File.Open(ofd.FileName, FileMode.Open))
{
List<shaypeh> shaypehs = (List<shaypeh>)serializer.Deserialize(stream);
foreach(shaypeh shape in shaypehs)
{
if (shape.getCircleOrSquare() == true)
{
Circle c = new Circle();
Canvas.SetTop(c, shape.getY());
Canvas.SetLeft(c, shape.getX());
c.PreviewMouseDown += c_PreviewMouseDown;
pictureBoard.Children.Add(c);
}
if (shape.getCircleOrSquare() == false)
{
Rectangle r = new Rectangle();
Canvas.SetTop(r, shape.getY());
Canvas.SetLeft(r, shape.getX());
r.PreviewMouseDown += c_PreviewMouseDown;
pictureBoard.Children.Add(r);
}
}
}
Any help/advice would be greatly appreciated.
The XmlSerializer
ignores private members.
You should implement shaypeh
as a C# type, i.e. replace the get*
methods with properties and change the names to comply with the common coding conventions:
[Serializable]
public class Shaypeh
{
public Shaypeh()
{
}
public Shaypeh(double x, double y, bool circleOrSquare)
{
this.X = x;
this.Y = y;
this.CircleOrSquare = circleOrSquare;
}
public bool CircleOrSquare { get; set; }
public double X { get; set; }
public double Y { get; set; }
}
Using the above implementation of Shaypeh
, your seralization code should work.