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

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

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

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

  1. void canvas1_Drop(object sender, DragEventArgs e)
  2. {
  3. IDataObject data = new DataObject();
  4. data = e.Data;
  5. if (data.GetDataPresent(typeof(Rectangle)))
  6. {
  7. Rectangle rect = new Rectangle();
  8. rect = data.GetData(typeof(Rectangle)) as Rectangle;
  9. canvas1.Children.Add(rect);
  10. }
  11. }

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

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

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

  1. void canvas1_Drop(object sender, DragEventArgs e)
  2. {
  3. IDataObject data = new DataObject();
  4. data = e.Data;
  5. if (data.GetDataPresent(typeof(Rectangle)))
  6. {
  7. Rectangle rect = new Rectangle();
  8. rect = data.GetData(typeof(Rectangle)) as Rectangle;
    canvas2.Children.Remove(rect);//
  9. canvas1.Children.Add(rect);
  10. }
  11. }

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

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

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

深拷贝,好了:

傻x一点办法如下:

  1. if (data.GetDataPresent(typeof(Rectangle)))
  2. {
  3. Rectangle dataobj = data.GetData(typeof(Rectangle)) as Rectangle;
  4. Rectangle rect = new Rectangle();
  5. rect.Height = dataobj.RenderSize.Height;
  6. rect.Width = dataobj.RenderSize.Width;
  7. rect.Fill = dataobj.Fill;
  8. rect.Stroke = dataobj.Stroke;
  9. rect.StrokeThickness = dataobj.StrokeThickness;
  10. canvas1.Children.Add(rect);
  11. rect.SetValue(Canvas.TopProperty, e.GetPosition(canvas1).Y);
  12. rect.SetValue(Canvas.LeftProperty, e.GetPosition(canvas1).X);
  13. }

问题是解决了,但这种代码明显丑陋!不堪入目~虽然是效果上实现了,但总感觉其中哪里影藏着一个定时炸弹,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.

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

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

  1. if (data.GetDataPresent(typeof(Rectangle)))
  2. {
  3. Rectangle rect = new Rectangle();
  4. rect = data.GetData(typeof(Rectangle)) as Rectangle;
  5. //canvas2.Children.Remove(rect);
  6. //canvas1.Children.Add(rect);
  7. //序列化Control,以深复制Control!!!!
  8. string rectXaml = XamlWriter.Save(rect);
  9. StringReader stringReader = new StringReader(rectXaml);
  10. XmlReader xmlReader = XmlReader.Create(stringReader);
  11. UIElement clonedChild = (UIElement)XamlReader.Load(xmlReader);
  12. canvas1.Children.Add(clonedChild);
  13. }

希望对你有帮助~

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

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

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

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

WPF控件深拷贝:序列化/反序列化的更多相关文章

  1. [转载]WPF控件拖动

    这篇博文总结下WPF中的拖动,文章内容主要包括: 1.拖动窗口 2.拖动控件 Using Visual Studio 2.1thumb控件 2.2Drag.Drop(不连续,没有中间动画) 2.3拖动 ...

  2. 浅尝辄止——使用ActiveX装载WPF控件

    1 引言 使用VC编写的容器类编辑器,很多都可以挂接ActiveX控件,因为基于COM的ActiveX控件不仅封装性不错,还可以显示一些不错的界面图元. 但是随着技术不断的进步,已被抛弃的Active ...

  3. XMAL语法系列之-(2)---WPF控件继承图

    WPF控件继承图 1 FrameworkElement 1.1 Panel(面板类元素) 1.1.1 Canvas 1.1.2 DockPanel 1.1.3 Grid 1.1.4 TabPanel ...

  4. 通过WinForm控件创建的WPF控件无法输入的问题

    今天把写的一个WPF程序发布到别的机器上执行,发现一个比较奇怪的问题:在那个机器上用英文输入法无法输入数字,非要切换到中文输入法才行:但在我的机器上却是好好的. 最开始以为是输入法的问题,弄了好一阵子 ...

  5. WPF控件--利用Winform库中的NotifyIcon实现托盘小程序

    WPF控件--NotifyIcon   运行界面如下所示:            图1                                             图2 代码很少,如下所示 ...

  6. (转)WPF控件开源资源

    (转)WPF控件开源资源 Textbox Drag/Drop in WPFhttp://www.codeproject.com/Articles/42696/Textbox-Drag-Drop-in- ...

  7. WPF控件模板

    引言:在进行WPF项目开发过程中,由于项目的需要,经常要对某个控件进行特殊的设定,其中就牵涉到模板的相关方面的内容.本文也是在自己进行项目开发过程中遇到控件模板设定时集中搜集资料后整理出来的,以供在以 ...

  8. 关于WinForm引用WPF窗体---在Winform窗体中使用WPF控件

    项目中有个界面展示用WPF实现起来比较简单,并且能提供更酷炫的效果,但是在WinForm中使用WPF窗体出现了问题,在网上找了一下有些人说Winform不能引用WPF的窗体,我就很纳闷,Win32都能 ...

  9. 我的WPF控件库——KAN.WPF.XCtrl(141105)

    自己开发的WPF控件库,只是初版,有扩展的Button,TextBox,Window.详细参见前几篇博文. WPF自定义控件(一)——Button:http://www.cnblogs.com/Qin ...

随机推荐

  1. (一一六)新浪微博client的离线缓存实现思路

    上一节(一一五)利用NSKeyedArchiver实现随意对象转为二进制介绍了将随意对象转化为二进制数据和还原的方法.可用于实现本节介绍的微博数据离线缓存. 通过新浪官方的API能够发现,返回的微博数 ...

  2. dnf游戏外怪原理

    dnf游戏外怪原理 一.总结 一句话总结:用钩子,修改内存.找到存储数据的内存,修改内存的执行代码达到修改数据的目的,修改了数据之后再改回来. 1.如何找到存储数据的内存? 然后数据变化,用软件找变化 ...

  3. Android中动态设置GridView的列数、列宽和行高

    在使用GridView时我们知道,列数是可以通过设计时的属性来设置的,列的宽度则是根据列数和GridView的宽度计算出来的.但是有些时候我们想实现列数是动态改变的效果,即列的宽度保持某个值,列的数量 ...

  4. 前端工具WebStorm好在哪里?(带详细破解教程)

    前端工具WebStorm好在哪里?(带详细破解教程) 一.总结 1.WebStorm对html特别是HTML5和JS的智能提示简直堪称大神. 2.WebStorm足够的轻量级. 3.WebStorm对 ...

  5. 【OpenGL】Shader实例分析(六)- 卡牌特效

    转发请保持地址:http://blog.csdn.net/stalendp/article/details/30989295 本文将介绍怎么通过alpha通道来隐藏信息.并实现卡牌特效. 执行效果例如 ...

  6. htmlunit 模拟登录 数字验证码

    使用htmlunit的好处有两点,相比httpclient,htmlunit是对浏览器的模拟,比如你定位一个按钮,就可以执行click()方法,此外不需要象在httpclient中一样编写复杂的代码, ...

  7. python于lxml应用

    首先下载lxml, http://www.lfd.uci.edu/~gohlke/pythonlibs/ ,然后加入引用 from lxml import _elementpath as DONTUS ...

  8. 经Gradle采取Jenkins的build

    如今,企业都太多Jenkins去管理apk,后该代码被提交jenkins在生成build 因此,我们可以得到jenkins提交版本 Jenkins在编制job什么时候,有一个内置的可变BUILD_NU ...

  9. 用表来管理SQLServer中的扩展属性(描写叙述)

    数据字典是个好东东,对于开发.维护很重要. 但Sql Server中写描写叙述确实不方便,怎样化繁为简.批量地添加改动扩展属性呢? 添加2个表和5个存储过程.2个触发器.1个表值函数就好了. 把以下的 ...

  10. apt-get install 的参数(add-apt-repository)

    apt-get install 是 ubuntu 下的软件安装命令. sudo apt-get -y install: -y:yes,在命令行交互提示中,直接输入 yes: 1. 使用 add-apt ...