2013-03-22 28 views
6

Tôi đã thử phương pháp này đầu tiên nhưng nhận được lỗi "phần tử đã là con của một phần tử"Làm thế nào để sao chép UIElement trong WinRT XAML C#?

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

Sau đó, tôi đã kiểm tra thisthis, nhưng XamlWriter và XamlReader không có sẵn trong WinRT. Tôi đã cố gắng sử dụng MemberwiseClone() nhưng nó ném ngoại lệ, "đối tượng COM đã được tách ra từ RCW cơ bản của nó không thể được sử dụng. System.Runtime.InteropServices.InvalidComObjectException". Vì vậy, bất cứ ai có thể cho tôi biết làm thế nào tôi có thể sao chép UserControl hiện có trong vải của tôi cho chính nó?

+2

Bạn đang cố gắng giải quyết vấn đề gì bằng cách sao chép UIElements? Có thể có một cách tốt hơn để đi về nó. –

Trả lời

1

Bạn có thể thử các bộ nối tiếp khác với XamlWriter và XamlReader để đạt được cùng một hiệu ứng được mô tả bởi các liên kết của bạn. Ví dụ, sử dụng ServiceStack.Text để JSON tuần tự hóa đối tượng của bạn thành một chuỗi, sau đó lấy một đối tượng mới từ chuỗi đó và thêm nó vào phụ huynh.

+0

Tôi đã thử Json.Net dưới dạng ServiceStack.Text không có sẵn trong WinRT. Unfortunaly nó là ném ngoại lệ trong khi serialization. Khi tôi sử dụng 'JsonConvert.SerializeObject (this)' nó ném 'StackOverflowException' và khi tôi sử dụng' JsonConvert.SerializeObjectAsync (this) 'nó ném' JsonSerializationException' (Lỗi nhận giá trị từ 'Watermark' trên 'Callisto.Controls.WatermarkTextBox') xin lưu ý điều khiển người dùng của tôi sử dụng điều khiển người dùng khác từ bộ công cụ như [Callisto] (https://github.com/timheuer/callisto) – Xyroid

+1

Sau đó, tôi sẽ đề nghị không nhân bản MyImageControl ở tất cả. Nếu hiệu ứng bạn muốn đạt được là, ví dụ, đặt hai mặt cười trên canvas là bản sao của nhau, thêm MyImageControl mới được tạo và đặt thuộc tính imageource (hoặc bất kỳ điều gì thích hợp) của điều khiển mới giống với Đầu tiên. Nếu bạn nói có quá nhiều thuộc tính để sao chép bằng tay, có các phương thức sử dụng sự phản chiếu để lặp qua các thuộc tính có sẵn và sao chép các giá trị của chúng. Ví dụ, xem http://stackoverflow.com/questions/1198886/c-sharp-using-reflection-to-copy-base-class-properties –

+0

Giải pháp trên cũng không hoạt động trong WinRT vì có hỗ trợ phương thức hạn chế trong WinRT cho [System.Reflection] (http://msdn.microsoft.com/en-us/library/42892f65.aspx) như 'Type.GetFields()' không có sẵn trong WinRT. – Xyroid

2

Tôi đã viết phần mở rộng UIElement sao chép thuộc tính và con của phần tử - lưu ý rằng nó không thiết lập sự kiện cho bản sao.

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); 
          } 
         } 
        } 
       } 
      } 
     }   
    } 
} 

Hãy sử dụng mã này nếu bạn thấy nó hữu ích.

Các vấn đề liên quan