WPF中Canvas多自定义UserControl序列化与反序列化问题求助
WPF Canvas 序列化/反序列化问题排查与修复
问题概述
尝试对WPF Canvas中的自定义UserControl(蓝色圆形、红色方形)进行序列化和反序列化,当前能正常保存/加载文件,但存在两个核心问题:
- 加载时仅生成红色方形,圆形完全不显示
- 生成的方形全部位于Canvas的(0,0)坐标,但形状数量与保存时一致
- 保存后的XML仅包含空的
<shaypeh />节点,未记录任何坐标和形状类型信息
相关代码
序列化存储类
[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; } }
保存Canvas代码
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); }
保存后的XML示例(添加2个圆形+1个方形后)
<?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>
加载文件代码
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); } } }
问题根源与修复方案
1. XmlSerializer无法序列化私有字段
XmlSerializer默认仅序列化公共属性,shaypeh类中的x、y、circleOrSquare均为私有字段,且无对应公共属性,导致序列化时无法写入任何数据,最终XML仅生成空节点。
修复:
将私有字段改为公共属性(符合C#编码规范):
[Serializable()] public class shaypeh { // 公共属性供XmlSerializer序列化 public double X { get; set; } public double Y { get; set; } public bool IsCircle { get; set; } public shaypeh() { } public shaypeh(double x, double y, bool isCircle) { X = x; Y = y; IsCircle = isCircle; } }
2. 保存代码中形状类型标记错误+坐标空值处理缺失
- 处理Rectangle时,传入的类型标记参数为
true(与Circle的标记一致),导致所有形状都被标记为圆形; - Canvas.GetTop/GetLeft在未显式设置坐标时会返回
null,直接赋值给double会引发隐式转换错误,导致坐标数据丢失。
修复保存代码:
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 circle) { // 处理null情况,默认坐标为0 double top = Canvas.GetTop(circle) ?? 0; double left = Canvas.GetLeft(circle) ?? 0; shaypehs.Add(new shaypeh(left, top, true)); } else if (obj is Rectangle rect) { double top = Canvas.GetTop(rect) ?? 0; double left = Canvas.GetLeft(rect) ?? 0; // Rectangle标记为false shaypehs.Add(new shaypeh(left, top, false)); } } XmlSerializer serializer = new XmlSerializer(typeof(List<shaypeh>)); using (FileStream stream = File.Create(sfd.FileName)) { serializer.Serialize(stream, shaypehs); }
3. 反序列化代码适配属性变更
更新反序列化代码,使用新的公共属性:
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.IsCircle) { Circle c = new Circle(); Canvas.SetTop(c, shape.Y); Canvas.SetLeft(c, shape.X); c.PreviewMouseDown += c_PreviewMouseDown; pictureBoard.Children.Add(c); } else { Rectangle r = new Rectangle(); Canvas.SetTop(r, shape.Y); Canvas.SetLeft(r, shape.X); r.PreviewMouseDown += c_PreviewMouseDown; pictureBoard.Children.Add(r); } } }
内容的提问来源于stack exchange,提问作者AJMullen
相关产品推荐
相关产品推荐

