2013-03-22 61 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); 
          } 
         } 
        } 
       } 
      } 
     }   
    } 
} 

如果您觉得它有帮助,请随时使用本代码。