zoukankan      html  css  js  c++  java
  • 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 Action View 以及监听 的使用
    15 ActionProvider代码例子
    15 ActionBar 总结
    15 Actionbar的显示和隐藏
    14 fragment传值
    14 fragment 创建
    14 Fragment 注意点
    14 Fragment 碎片总结
    GSON TypeToken 解决泛型问题
    Intent传递对象——Serializable和Parcelable区别
  • 原文地址:https://www.cnblogs.com/DebugLZQ/p/3062409.html
Copyright © 2011-2022 走看看