2013-03-22 144 views
6

我也第一次嘗試這種做法,但得到的錯誤「元素已經是另一個元素的孩子」如何在WinRT XAML C#中克隆UIElement?

var objClone = new MyImageControl(); 
objClone = this; 
((Canvas)this.Parent).Children.Add(objClone); 

然後我檢查thisthis,但和的XamlWriter是XamlReader無法在WinRT中。我試圖使用MemberwiseClone(),但它拋出異常,「已經從其基礎RCW分離的COM對象不能使用。」System.Runtime.InteropServices.InvalidComObjectException「。那麼有誰能告訴我如何將我的畫布中的現有UserControl克隆到自己?

+2

你想通過克隆UIElements解決什麼問題?可能有更好的方式去實現它。 – 2013-03-22 07:29:39

回答

1

您可以嘗試使用XamlWriter和XamlReader以外的序列化程序來實現鏈接描述的效果。例如,使用ServiceStack.Text將JSON序列化爲字符串,然後從該字符串獲取新對象並將其添加到父對象。

+0

我試過Json.Net,因爲ServiceStack.Text在WinRT中不可用。不幸的是它在序列化時拋出異常。當我使用'JsonConvert.SerializeObject(this)'它拋出'StackOverflowException'並且當我使用'JsonConvert.SerializeObjectAsync(this)'時拋出'JsonSerializationException'(錯誤從'Waterist'獲取'Callisto.Controls.WatermarkTextBox'的值)請注意我的用戶控件使用工具包中的其他用戶控件,例如[Callisto](https://github.com/timheuer/callisto) – Xyroid 2013-03-22 09:42:23

+1

然後我建議不要克隆MyImageControl。例如,如果要實現的效果是在畫布上放置兩個互相重複的笑臉,請添加新創建的MyImageControl,並將新控件的圖像源(或其他適當的)屬性設置爲第一。如果您說有太多的屬性需要手動複製,則有些方法會使用反射來遍歷可用屬性並複製其值。有關示例,請參閱http://stackoverflow.com/questions/1198886/c-sharp-using-reflection-to-copy-base-class-properties – 2013-03-22 11:15:25

+0

上述解決方案在WinRT中也不起作用,因爲WinRT for [System.Reflection](http://msdn.microsoft.com/en-us/library/42892f65.aspx)像'Type.GetFields()'在WinRT中不可用。 – Xyroid 2013-03-22 12:18:51

2

我已經寫了一個UIElement擴展名,用於複製元素的屬性和子元素 - 請注意,它確實爲而不是設置了克隆的事件。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using Windows.UI.Xaml; 
using System.Reflection; 
using Windows.UI.Xaml.Controls; 

namespace UIElementClone 
{ 
    public static class UIElementExtensions 
    { 
     public static T DeepClone<T>(this T source) where T : UIElement 
     { 

      T result; 

      // Get the type 
      Type type = source.GetType(); 

      // Create an instance 
      result = Activator.CreateInstance(type) as T; 

      CopyProperties<T>(source, result, type); 

      DeepCopyChildren<T>(source, result); 

      return result; 
     } 

     private static void DeepCopyChildren<T>(T source, T result) where T : UIElement 
     { 
      // Deep copy children. 
      Panel sourcePanel = source as Panel; 
      if (sourcePanel != null) 
      { 
       Panel resultPanel = result as Panel; 
       if (resultPanel != null) 
       { 
        foreach (UIElement child in sourcePanel.Children) 
        { 
         // RECURSION! 
         UIElement childClone = DeepClone(child); 
         resultPanel.Children.Add(childClone); 
        } 
       } 
      } 
     } 

     private static void CopyProperties<T>(T source, T result, Type type) where T : UIElement 
     { 
      // Copy all properties. 

      IEnumerable<PropertyInfo> properties = type.GetRuntimeProperties(); 

      foreach (var property in properties) 
      { 
       if (property.Name != "Name") // do not copy names or we cannot add the clone to the same parent as the original. 
       { 
        if ((property.CanWrite) && (property.CanRead)) 
        { 
         object sourceProperty = property.GetValue(source); 

         UIElement element = sourceProperty as UIElement; 
         if (element != null) 
         { 
          UIElement propertyClone = element.DeepClone(); 
          property.SetValue(result, propertyClone); 
         } 
         else 
         { 
          try 
          { 
           property.SetValue(result, sourceProperty); 
          } 
          catch (Exception ex) 
          { 
           System.Diagnostics.Debug.WriteLine(ex); 
          } 
         } 
        } 
       } 
      } 
     }   
    } 
} 

如果您覺得它有幫助,請隨時使用本代碼。