2013-10-14 2 views
0

사용자 지정 시각적 요소가 있으며 실버 라이트 응용 프로그램에서 딥 복사본을 만들고 싶습니다.Silverlight4 딥 복사 시각적 요소

많은 것들을 시도했지만 어떤 해결책도 찾지 못했습니다. 원래 DeviceControl과 사본이 링크 된 가장 좋은 해결책은 여기에 링크되어 있습니다. 둘 중 하나의 속성을 변경하면 두 번째 속성도 변경됩니다. 나는 그들이 독립하기를 바란다!

아이디어가 있으십니까?

void CloneDevice() 
{ 
DeviceControl control = this; 
DeviceControl copy = CloneObject.DeepClone<DeviceControl>(control); 
ExtensionMethods.DeepCopy(control, copy); 
} 

//[Obfuscation(Exclude = true)] 
    internal static class CloneObject 
    { 
     private static bool _firstTry = false; 

     private static List<FieldInfo> _attachedProperties = null; 

     // Extension for any class object 
     internal static TT DeepClone<TT>(this TT source, bool?cloneAttachedProperties = null) 
     { // Jim McCurdy's DeepClone 
      if (cloneAttachedProperties == null) 
       cloneAttachedProperties = (source is DependencyObject); 

      // The first time this method is called, compute a list of all 
      // attached properties that exist in this XAP's assemblies 
      if (cloneAttachedProperties == true && _attachedProperties == null) 
      { 
       _attachedProperties = new List<FieldInfo>(); 
       List<Assembly> assemblies = GetLoadedAssemblies(); 
       foreach (Assembly assembly in assemblies) 
        GetAttachedProperties(_attachedProperties, assembly); 
      } 

      TT clone = CloneRecursive(source); 

      if (clone is FrameworkElement) 
      { 
       FrameworkElement cloneElement = (clone as FrameworkElement); 
       cloneElement.Arrange(new Rect(0, 0, cloneElement.ActualWidth, cloneElement.ActualHeight)); 
      } 

      return clone; 
     } 

     private static TT CloneRecursive<TT>(TT source) 
     { 
      if (source == null || source.GetType().IsValueType) 
       return source; 

      // Common types that do not have parameterless constructors 
      if (source is string || source is Type || source is Uri || source is DependencyProperty) 
       return source; 

      TT clone = CloneCreate(source); 
      if (clone == null) 
       return source; 

      if (source is IList) 
       CloneList(source as IList, clone as IList); 

      //CloneProperties(source, clone);//ca plante si on prend les propriétées comme ca 

      return clone; 
     } 

     private static TT CloneCreate<TT>(TT source) 
     { 
      try 
      { 
#if DEBUG_TRACE 
      string.Format("Clone create object Type={0}", SimpleType(source.GetType())).Trace(); 
#endif 
       Array sourceArray = (source as Array); 
       if (sourceArray == null) 
        return (TT)Activator.CreateInstance(source.GetType()); 
       if (sourceArray.Rank == 1) 
        return (TT)(object)Array.CreateInstance(source.GetType().GetElementType(), 
         sourceArray.GetLength(0)); 
       if (sourceArray.Rank == 2) 
        return (TT)(object)Array.CreateInstance(source.GetType().GetElementType(), 
         sourceArray.GetLength(0), sourceArray.GetLength(1)); 
      } 
      catch (Exception ex) 
      { 
       if (ex.Message.Contains("No parameterless constructor")) 
        return default(TT); 
       //string.Format("Can't create object Type={0}", SimpleType(source.GetType())).Trace(); 
       //ex.DebugOutput(); 
      } 

      return default(TT); 
     } 

     private static void CloneProperties(object source, object clone) 
     { 
      // The binding flags indicate what properties we will clone 
      // Unfortunately, we cannot clone "internal" or "protected" properties 
      BindingFlags flags = 
       BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.Public; 

      if (source is DependencyObject) 
      { 
       DependencyObject sourcedp = source as DependencyObject; 
       DependencyObject clonedp = clone as DependencyObject; 

       // Clone attached properties 
       if (_attachedProperties != null && _attachedProperties.Count > 0) 
        foreach (FieldInfo field in _attachedProperties) 
         CloneDependencyProperty(sourcedp, clonedp, field, true); 

       // Clone dependency properties 
       FieldInfo[] fields = source.GetType().GetFields(flags | BindingFlags.Static); 
       foreach (FieldInfo field in fields) 
        CloneDependencyProperty(sourcedp, clonedp, field, false); 
      } 

      // Clone CLR properties 
      if (source is DeviceControl && _firstTry == false) 
      { 
       _firstTry = true; 
       PropertyInfo[] properties = source.GetType().GetProperties(flags); 
       foreach (PropertyInfo property in properties) 
        CloneProperty(source, clone, property); 
      } 
     } 

     private static void CloneDependencyProperty(DependencyObject sourceObject, 
      DependencyObject cloneObject, FieldInfo field, bool isAttached) 
     { 
      try 
      { 
       // Blacklisted properties that can't (or shouldn't) be set 
       if (field.Name == "NameProperty" && sourceObject is FrameworkElement) return; 

       DependencyProperty dp = field.GetValue(sourceObject) as DependencyProperty; 
       if (dp == null) // Event DependencyProperties will be null 
        return; 

       object sourceValue = null; 
       try 
       { 
        sourceValue = sourceObject.GetValue(dp); 
       } 
       catch (Exception) 
       { 
       } 

       if (sourceValue == null) 
        return; 
       // Don't set attached properties if we don't have to 
       if (isAttached) 
       { 
        Type sourceType = sourceValue.GetType(); 
        if (sourceType.IsValueType && sourceValue.Equals(Activator.CreateInstance(sourceType))) 
         return; 
       } 
#if DEBUG_TRACE 
      string.Format("Clone dependency property Name={0}, Value={2} for source Type={1}", 
       field.Name, SimpleType(sourceObject.GetType()), sourceValue).Trace(); 
#endif 
       // Blacklisted properties that can't (or don't need to be) cloned 
       bool doClone = true; 
       if (field.Name == "DataContextProperty") doClone = false; 
       //if (field.Name == "TargetPropertyProperty") doClone = false; 

       object cloneValue = (doClone ? CloneRecursive(sourceValue) : sourceValue); 
       cloneObject.SetValue(dp, cloneValue); 
      } 
      catch (Exception ex) 
      { 
       if (ex.Message.Contains("read-only")) 
        return; 
       if (ex.Message.Contains("read only")) 
        return; 
       if (ex.Message.Contains("does not fall within the expected range")) 
        return; 
       //string.Format("Can't clone dependency property Name={0}, for source Type={1}", 
       // field.Name, SimpleType(sourceObject.GetType())).Trace(); 
       //ex.DebugOutput(); 
      } 
     } 

     private static void CloneProperty(object source, object clone, PropertyInfo property) 
     { 
      try 
      { 
       if (!property.CanRead || !property.CanWrite || property.GetIndexParameters().Length != 0) 
        return; 

       // Blacklisted properties that can't (or shouldn't) be set 
       if (property.Name == "Name" && source is FrameworkElement) return; 
       if (property.Name == "InputScope" && source is TextBox) return; // Can't get 
       if (property.Name == "Watermark" && source is TextBox) return; // Can't get 
       if (property.Name == "Source" && source is ResourceDictionary) return; // Can't set 
       if (property.Name == "TargetType" && source is ControlTemplate) return; // Can't set 

       bool publicSetter = (source.GetType().GetMethod("set_" + property.Name) != null); 
       bool isList = (property.PropertyType.GetInterface("IList", true) != null); 
       if (!publicSetter && !isList) 
        return; 

       object sourceValue = property.GetValue(source, null); 
       if (sourceValue == null) 
        return; 

       if (!publicSetter && isList) 
       { 
        IList cloneList = property.GetValue(clone, null) as IList; 
        if (cloneList != null) 
         CloneList(sourceValue as IList, cloneList); 
        return; 
       } 
#if DEBUG_TRACE 
      string.Format("Clone property Type={0}, Name={1}, Value={3} for source Type={2}", 
       SimpleType(property.PropertyType), property.Name, SimpleType(source.GetType()), 
       sourceValue).Trace(); 
#endif 
       // Blacklisted properties that can't (or don't need to be) cloned 
       bool doClone = true; 
       if (source is FrameworkElement && property.Name == "DataContext") doClone = false; 
       //if (property.Name == "TargetProperty") doClone = false; 

       object cloneValue = (doClone ? CloneRecursive(sourceValue) : sourceValue); 
       property.SetValue(clone, cloneValue, null); // possible MethodAccessException 
      } 
      catch (Exception ex) 
      { 
       //string.Format("Can't clone property Type={0}, Name={1}, for source Type={2}", 
       // SimpleType(property.PropertyType), property.Name, SimpleType(source.GetType())).Trace(); 
       //ex.DebugOutput(); 
      } 
     } 

     private static void CloneList(IList sourceList, IList cloneList) 
     { 
      try 
      { 
       IEnumerator sourceEnumerator = sourceList.GetEnumerator(); 
       Array sourceArray = sourceList as Array; 
       Array cloneArray = cloneList as Array; 
       int dim0 = (sourceArray != null && sourceArray.Rank > 0 ? sourceArray.GetLowerBound(0) : 0); 
       int dim1 = (sourceArray != null && sourceArray.Rank > 1 ? sourceArray.GetLowerBound(1) : 0); 

       while (sourceEnumerator.MoveNext()) 
       { 
        object sourceValue = sourceEnumerator.Current; 
#if DEBUG_TRACE 
       string.Format("Clone IList item {0}", sourceValue).Trace(); 
#endif 
        object cloneValue = CloneRecursive(sourceValue); 
        if (sourceArray == null) 
         cloneList.Add(cloneValue); 
        else 
         if (sourceArray.Rank == 1) 
          cloneArray.SetValue(cloneValue, dim0++); 
         else 
          if (sourceArray.Rank == 2) 
          { 
           cloneArray.SetValue(cloneValue, dim0, dim1); 
           if (++dim1 > sourceArray.GetUpperBound(1)) 
           { 
            dim1 = sourceArray.GetLowerBound(1); 
            if (++dim0 > sourceArray.GetUpperBound(0)) 
             dim0 = sourceArray.GetLowerBound(0); 
           } 
          } 
       } 
      } 
      catch (Exception ex) 
      { 
       //string.Format("Can't clone IList item Type={0}", SimpleType(sourceList.GetType())).Trace(); 
       //ex.DebugOutput(); 
      } 
     } 

     private static string SimpleType(Type type) 
     { 
      string typeName = type.ToString(); 
      int index = typeName.LastIndexOf('['); 
      if (index < 0) 
       return typeName.Substring(typeName.LastIndexOf('.') + 1); 

      string collectionName = typeName.Substring(index); 
      collectionName = collectionName.Substring(collectionName.LastIndexOf('.') + 1); 
      typeName = typeName.Substring(0, index); 
      typeName = typeName.Substring(typeName.LastIndexOf('.') + 1); 
      return typeName + '[' + collectionName; 
     } 

     private static List<Assembly> GetLoadedAssemblies() 
     { 
      List<Assembly> assemblies = new List<Assembly>(); 

      foreach (AssemblyPart part in Deployment.Current.Parts) 
      { 
       StreamResourceInfo sri = 
        Application.GetResourceStream(new Uri(part.Source, UriKind.Relative)); 
       if (sri == null) 
        continue; 
       Assembly assembly = new AssemblyPart().Load(sri.Stream); 
       if (assembly != null && !assemblies.Contains(assembly)) 
        assemblies.Add(assembly); 
      } 

      // Additional assemblies that are not found when examining of Deployment.Current.Parts above 
      Type[] types = 
     { 
      typeof(System.Windows.Application), // System.Windows.dll, 
      #if INCLUDE_ASSEMBLIES_WITHOUT_ATTACHED_PROPERTIES 
      typeof(System.Action), // mscorlib.dll, 
      typeof(System.Uri), // System.dll, 
      typeof(System.Lazy<int>), // System.Core.dll, 
      typeof(System.Net.Cookie), // System.Net.dll, 
      typeof(System.Runtime.Serialization.StreamingContext), // System.Runtime.Serialization.dll, 
      typeof(System.ServiceModel.XmlSerializerFormatAttribute), // System.ServiceModel.dll, 
      typeof(System.Windows.Browser.BrowserInformation), // System.Windows.Browser.dll, 
      typeof(System.Xml.ConformanceLevel), // System.Xml.dll, 
      #endif 
     }; 

      foreach (Type type in types) 
      { 
       Assembly assembly = type.Assembly; 
       if (assembly != null && !assemblies.Contains(assembly)) 
        assemblies.Add(assembly); 
      } 

      return assemblies; 
     } 

     private static bool GetAttachedProperties(List<FieldInfo> attachedProperties, Assembly assembly) 
     { 
      BindingFlags flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Static; 
      foreach (Type type in assembly.GetTypes()) 
      { 
       FieldInfo[] fields = type.GetFields(flags); 
       MethodInfo[] methods = null; 
       foreach (FieldInfo field in fields) 
       { 
        if (field.FieldType==(typeof(DependencyProperty))) 
         continue; 
        if (!field.Name.EndsWith("Property")) 
         continue; 

        string fieldName = field.Name.Replace("Property", ""); 
        string getName = "Get" + fieldName; 
        string setName = "Set" + fieldName; 
        bool foundGet = false; 
        bool foundSet = false; 
        if (methods == null) 
         methods = type.GetMethods(flags); 
        foreach (MethodInfo method in methods) 
        { 
         if (method.Name == getName && method.GetParameters().Length == 1 && 
          method.GetParameters()[0].ParameterType== (typeof(DependencyObject))) 
          foundGet = true; 
         else 
          if (method.Name == setName && method.GetParameters().Length == 2 && 
           method.GetParameters()[0].ParameterType==(typeof(DependencyObject))) 
           foundSet = true; 
         if (foundGet && foundSet) 
          break; 
        } 

        if (!(foundGet && foundSet)) 
         continue; 

        try 
        { 
         DependencyProperty dp = field.GetValue(null) as DependencyProperty; 
        } 
        catch (Exception) 
        { 
         continue; 
        } 

        // Found an attached Dependency Property 
        attachedProperties.Add(field); 
       } 
      } 

      return true; 
     } 
    } 

public static void DeepCopy(object source, object destination) 
     { 
      // Get properties 
      var propertyInfos = source.GetType().GetProperties(); 
      // Evaluate 
      if (propertyInfos.Length > 0) 
      { 
       foreach (var propInfo in propertyInfos) 
       { 
        // Process only public properties 
        if (propInfo.CanWrite) 
        { 
         if (propInfo.Name == "IsSelected") 
         { 
          break; 
         } 
         else 
         { 
          object value = propInfo.GetValue(source, null); 
          propInfo.SetValue(destination, value, null); 

          // Evaluate 
          if (value != null) 
          { 
           var newPropInfo = value.GetType().GetProperties(); 
           if (newPropInfo.Length > 0) 
           { 
            // Copy properties for each child where necessary 
            DeepCopy(
             source.GetType().GetProperty(propInfo.Name), 
             destination.GetType().GetProperty(propInfo.Name)); 
           } 
          } 
         } 
        } 
       } 
      } 
     } 
+0

아무도 도와 줄 수 없나요? – user1343960

답변

0

문제점을 해결했습니다. 마침내 JSon.net 라이브러리를 사용했습니다.

void CloneDevice() 
{ 
    DeviceControl control = this; 
    string json = JsonConvert.SerializeObject(control, Formatting.Indented); 
    DeviceControl copy = (DeviceControl)JsonConvert.DeserializeObject(json, this.GetType()); 
} 

Olivier Dahan에게 감사드립니다!