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 覺得寫得沒有我的好,大家也可以看下~

 

沒什么高端的東西,老鳥繞過,輕拍~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM