2013-03-22 16 views
6

Ho provato questo approccio prima ma ottenere errore "Elemento è già il figlio di un altro elemento"Come clonare UIElement in WinRT XAML C#?

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

Poi ho controllato this e this, ma XamlWriter e XamlReader non è disponibile in WinRT. Ho provato a utilizzare MemberwiseClone() ma genera un'eccezione, "Impossibile rimuovere l'oggetto COM che è stato separato dal relativo RCW sottostante. System.Runtime.InteropServices.InvalidComObjectException". Quindi qualcuno può dirmi come posso clonare a se stesso l'UserControl esistente nella mia tela?

+2

Quale problema stai cercando di risolvere clonando UIElements? Forse c'è un modo migliore per farlo. –

risposta

1

È possibile provare i serializzatori diversi da XamlWriter e XamlReader per ottenere lo stesso effetto descritto dai collegamenti. Ad esempio, da ServiceStack.Text a JSON serializza il tuo oggetto su una stringa, quindi ottieni un nuovo oggetto da quella stringa e aggiungilo al genitore.

+0

Ho provato Json.Net come ServiceStack.Text non è disponibile in WinRT. Sfortunatamente lancia un'eccezione durante la serializzazione. Quando ho usato 'JsonConvert.SerializeObject (this)' lancia 'StackOverflowException' e quando ho usato' JsonConvert.SerializeObjectAsync (this) 'getta' JsonSerializationException' (Errore durante il recupero di valore da 'Watermark' su 'Callisto.Controls.WatermarkTextBox') per favore nota che i miei controlli utente usano altri controlli utente da toolkit come [Callisto] (https://github.com/timheuer/callisto) – Xyroid

+1

Quindi suggerirei di non clonare affatto MyImageControl. Se l'effetto che si desidera ottenere è, ad esempio, mettere due faccine sulla tela che sono duplicate l'una dell'altra, aggiungere un MyImageControl appena creato e impostare la proprietà imagesource (o qualsiasi altra cosa appropriata) del nuovo controllo identico a primo. Se dici che ci sono troppe proprietà da copiare a mano, ci sono metodi che usano il reflection per scorrere tra le proprietà disponibili e copiarne i valori. Per un esempio, vedere http://stackoverflow.com/questions/1198886/c-sharp-using-reflection-to-copy-base-class-properties –

+0

Anche la soluzione di cui sopra non funziona in WinRT poiché il supporto del metodo è limitato in WinRT per [System.Reflection] (http://msdn.microsoft.com/en-us/library/42892f65.aspx) come 'Type.GetFields()' non è disponibile in WinRT. – Xyroid

2

Ho scritto un'estensione UIElement che copia le proprietà e i figli di un elemento. Si noti che fa non impostare un evento per il clone.

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

Sentiti libero di usare questo codice se lo trovi utile.

Problemi correlati