WPF控件深拷贝:序列化/反序列化

简介: 原文:WPF控件深拷贝:序列化/反序列化今天DebugLZQ在做WPF拖动总结的时候,遇到了这个问题。baidu了下,貌似没有解决这个问题的权威答案,遂写下这篇博文。 我想做的事情是:拖动一个窗体内的控件(Rectangle)到另一个容器控件内,而保留原来的控件。
原文: WPF控件深拷贝:序列化/反序列化

今天DebugLZQ在做WPF拖动总结的时候,遇到了这个问题。baidu了下,貌似没有解决这个问题的权威答案,遂写下这篇博文。

我想做的事情是:拖动一个窗体内的控件(Rectangle)到另一个容器控件内,而保留原来的控件。

为了更好地把问题说清楚,请看如下代码片段:

void canvas1_Drop(object sender, DragEventArgs e)
{
   IDataObject data = new DataObject();
   data = e.Data;
   if (data.GetDataPresent(typeof(Rectangle)))
   {
      Rectangle rect = new Rectangle();
      rect = data.GetData(typeof(Rectangle)) as Rectangle;                
      canvas1.Children.Add(rect);                
   }
}

最后一行代码报告这样的运行时异常:

Specified element is already the logical child of another element. Disconnect it first

这是控件拷贝的问题。为了解决这个问题,我们可以这样:

void canvas1_Drop(object sender, DragEventArgs e)
{
   IDataObject data = new DataObject();
   data = e.Data;
   if (data.GetDataPresent(typeof(Rectangle)))
   {
      Rectangle rect = new Rectangle();
      rect = data.GetData(typeof(Rectangle)) as Rectangle;
canvas2.Children.Remove(rect);// canvas1.Children.Add(rect); } }

以上代码,是能消除这个异常,但是,被拖动的控件也没了。如果需求是不保留原来这个Rectangle,问题也就解决了,DebugLZQ也没有必要写这篇博文分享给各位。

既然控件直接拿过来行不通,那么这么解决呢?

容易想到的方法是复制这个控件。但是如你所见,上面的复制方法明显行不通,属于引用对象的拷贝,只拷贝了一个指针,其实是同一个对象。

深拷贝,好了:

傻x一点办法如下:

if (data.GetDataPresent(typeof(Rectangle))) 
{ 
   Rectangle dataobj = data.GetData(typeof(Rectangle)) as Rectangle; 
   Rectangle rect = new Rectangle(); 
   rect.Height = dataobj.RenderSize.Height; 
   rect.Width = dataobj.RenderSize.Width; 
   rect.Fill = dataobj.Fill; 
   rect.Stroke = dataobj.Stroke; 
   rect.StrokeThickness = dataobj.StrokeThickness; 
   canvas1.Children.Add(rect); 
   rect.SetValue(Canvas.TopProperty, e.GetPosition(canvas1).Y); 
   rect.SetValue(Canvas.LeftProperty, e.GetPosition(canvas1).X); 
}

问题是解决了,但这种代码明显丑陋!不堪入目~虽然是效果上实现了,但总感觉其中哪里影藏着一个定时炸弹,DebugLZQ惶惶不可终日;再退一步讲,即使这样没有问题,但是1个rectangle就得如此大费周章,要是来个for循环怎么办?!
因此这种解决方法绝非可接受!

You can clone a control by first serializing it using XamlWriter and then create a new control by deserializing it using XamlReader.

英文就是好,本来中文啰嗦一大堆的东西,一句话就写完了!

我们可以(深)拷贝这个控件采用序列化/反序列化的方式!实现如下:

if (data.GetDataPresent(typeof(Rectangle)))
{
   Rectangle rect = new Rectangle();
   rect = data.GetData(typeof(Rectangle)) as Rectangle;
   //canvas2.Children.Remove(rect);
   //canvas1.Children.Add(rect);
   //序列化Control,以深复制Control!!!!
   string rectXaml = XamlWriter.Save(rect);
   StringReader stringReader = new StringReader(rectXaml);
   XmlReader xmlReader = XmlReader.Create(stringReader);
   UIElement clonedChild = (UIElement)XamlReader.Load(xmlReader);
   canvas1.Children.Add(clonedChild);
}

 希望对你有帮助~

 很久没有把博文发到首页了,这篇发一下吧,老鸟飞过,轻拍~

这篇博文说白了,就是序列化/反序列化。更一般的方法,请参考DebugLZQ的博文:总结.NET中的:赋值VS浅拷贝VS深拷贝[序列化/反序列化]

tips:今天在codeproject上看到一篇类似的文章,XAML Serialization 觉得写得没有我的好,大家也可以看下~

 

没什么高端的东西,老鸟绕过,轻拍~

目录
相关文章
|
15天前
|
C# 开发者 Windows
基于Material Design风格开源、易用、强大的WPF UI控件库
基于Material Design风格开源、易用、强大的WPF UI控件库
|
1月前
|
存储 C#
C#中的序列化和反序列化
C#中的序列化和反序列化
12 0
|
1月前
|
存储 Java 数据库
|
3月前
|
Go
golang力扣leetcode 297.二叉树的序列化与反序列化
golang力扣leetcode 297.二叉树的序列化与反序列化
24 0
|
4月前
|
存储 算法
【每日一题Day316】LC449序列化和反序列化二叉搜索树 | BFS
【每日一题Day316】LC449序列化和反序列化二叉搜索树 | BFS
25 0
|
4月前
|
C#
浅谈WPF之装饰器实现控件锚点
使用过visio的都知道,在绘制流程图时,当选择或鼠标移动到控件时,都会在控件的四周出现锚点,以便于修改大小,移动位置,或连接线等,那此功能是如何实现的呢?在WPF开发中,想要在控件四周实现锚点,可以通过装饰器来实现,今天通过一个简单的小例子,简述如何在WPF开发中,应用装饰器,仅供学习分享使用,如有不足之处,还请指正。
65 1
|
3月前
|
存储 算法 C++
leetcode-297:二叉树的序列化与反序列化
leetcode-297:二叉树的序列化与反序列化
22 1
|
3月前
|
分布式计算 Java 大数据
IO流【Java对象的序列化和反序列化、File类在IO中的作用、装饰器模式构建IO流体系、Apache commons-io工具包的使用】(四)-全面详解(学习总结---从入门到深化)
IO流【Java对象的序列化和反序列化、File类在IO中的作用、装饰器模式构建IO流体系、Apache commons-io工具包的使用】(四)-全面详解(学习总结---从入门到深化)
53 0
|
11天前
|
存储 Java
Java输入输出:解释一下序列化和反序列化。
Java中的序列化和反序列化是将对象转换为字节流和反之的过程。ObjectOutputStream用于序列化,ObjectInputStream则用于反序列化。示例展示了如何创建一个实现Serializable接口的Person类,并将其序列化到文件,然后从文件反序列化回Person对象。
18 5
|
1月前
|
存储 C#
C#中的序列化和反序列化案例
C#中的序列化和反序列化案例
11 0