2008-08-28 7 views
34

누구나 데이터 바인딩을 유지하면서 WPF 객체를 깊이 복제하는 좋은 예가 있습니까?WPF 객체를 어떻게 복제 할 수 있습니까?


표시된 대답은 첫 번째 부분입니다.

두 번째 부분은 ExpressionConverter를 만들어 직렬화 프로세스에 삽입해야한다는 것입니다. 이에 대한 자세한 내용은 여기 있습니다 :
http://www.codeproject.com/KB/WPF/xamlwriterandbinding.aspx?fid=1428301&df=90&mpp=25&noise=3&sort=Position&view=Quick&select=2801571

답변

53

내가 한 가장 간단한 방법은 XamlWriter를 사용하여 WPF 개체를 문자열로 저장하는 것입니다. Save 메서드는 개체와 논리 트리의 모든 자식을 serialize합니다. 이제 새 개체를 만들고 XamlReader를 사용하여 개체를로드 할 수 있습니다.

예 : 새로운 객체로

string gridXaml = XamlWriter.Save(myGrid); 

로드를 : XAML에 객체 쓰기 (의 개체가 Grid 컨트롤을했다 가정 해 봅시다) .NET 4.0에서

StringReader stringReader = new StringReader(gridXaml); 
XmlReader xmlReader = XmlReader.Create(stringReader); 
Grid newGrid = (Grid)XamlReader.Load(xmlReader); 
+1

하십시오. – toad

+0

나는 생각하지 않는다 –

+7

분명히 말해서, 이것은 솔루션의 절반에 지나지 않습니다 (08로 되돌아갔습니다). 그러면 바인딩이 평가되고 결과가 직렬화됩니다. 바인딩을 유지하려는 경우 (질문으로 질문) 당신은 런타임에 바인딩 유형에 ExpressionConverter를 추가하거나 (해당 링크에 대한 내 질문의 두 번째 부분을 참조) 또는 4.0에서 수행하는 방법에 대한 내 자신의 대답을 참조하십시오. – Will

-1

방법에 대해 :

public static T DeepClone<T>(T from) 
    { 
     using (MemoryStream s = new MemoryStream()) 
     { 
      BinaryFormatter f = new BinaryFormatter(); 
      f.Serialize(s, from); 
      s.Position = 0; 
      object clone = f.Deserialize(s); 

      return (T)clone; 
     } 
    } 
물론

이 깊은 클론을 개체하고, 마을에서 가장 빠른 솔루션이 아닐 수도 있지만, 그것은 적어도 유지 보수가 있습니다 .. .

+4

이 WPF 객체 = 작동하지 않습니다 ( –

30

새로운 xaml 직렬화 스택을 사용하면이 작업이 훨씬 쉬워집니다.

var sb = new StringBuilder(); 
var writer = XmlWriter.Create(sb, new XmlWriterSettings 
{ 
    Indent = true, 
    ConformanceLevel = ConformanceLevel.Fragment, 
    OmitXmlDeclaration = true, 
    NamespaceHandling = NamespaceHandling.OmitDuplicates, 
}); 
var mgr = new XamlDesignerSerializationManager(writer); 

// HERE BE MAGIC!!! 
mgr.XamlWriterMode = XamlWriterMode.Expression; 
// THERE WERE MAGIC!!! 

System.Windows.Markup.XamlWriter.Save(this, mgr); 
return sb.ToString(); 
+0

XamlWriter.Save를 사용하는 것과 다른 점이 있습니까? 적어도 DataGrid를 serialize 할 때 다른 결과가 표시되지 않았습니다. –

+4

@JP 죄송합니다.이 모든 것이 명확하지는 않습니다. 문제는 바인딩을 보존하면서 * 복제하는 방법이었습니다. 표시된 대답은 반정도입니다. 사실, 그렇게하면 바인딩이 평가되고 바인딩 자체가 아니라 결과가 직렬화됩니다.내 질문에, 나는 ExpressionConverter를 추가하고 런타임에 바인딩 유형에 추가하는 솔루션에 후반부를 추가했습니다. 그것의 약간은 애매합니다. 이 대답으로 같은 것을 달성 할 수 있습니다 - MAGIC 코멘트가 있습니까? 직렬화하는 동안 바인딩을 평가하기 위해 serializer에게 ** not **를 지시합니다. 산뜻한. – Will

+0

예, 나는 이것을 보았습니다. 나는 여전히 내 Datagrid와 동일한 문제에 대해 작업 중이며 데이터 바인딩과 관련하여 다른 결과를 발견하지 못했습니다. 내 Datagrid는 여전히 비어 있습니다. 나는 다른 것을 놓치고 있어야합니다. 더 적은 것, 나는 당신에게 이것 모두를 지적하기위한 upvote를 줄 것이다. –

4

여기에 몇 가지 좋은 답변이 있습니다. 매우 도움이됩니다. http://pjlcon.wordpress.com/2011/01/14/change-a-wpf-binding-from-sync-to-async-programatically/에 설명 된 접근 방법을 포함하여 바인딩 정보를 복사하기위한 다양한 접근법을 시도했지만 여기 정보는 인터넷에서 최고입니다!

"사용 후 바인딩을 변경할 수 없습니다."라고 생각하는 InvalidOperationException을 처리 할 수있는 재사용 확장 메서드를 만들었습니다. 제 시나리오에서는 누군가가 작성한 코드를 유지 관리하고 DevExpress DXGrid 프레임 워크를 업그레이드 한 후 더 이상 일하지 않았다. 다음은 내 문제를 완벽하게 해결했습니다. 객체를 반환하는 코드 부분이 더 좋을 수 있으며 나중에 다시 생각할 것입니다. 그것은 또한 그들이 동일한 루트 컨테이너가 배치 될 경우 자신의 UI 요소에 사용 복잡하게 이름을 클론 마음에

/// <summary> 
/// Extension methods for the WPF Binding class. 
/// </summary> 
public static class BindingExtensions 
{ 
    public static BindingBase CloneViaXamlSerialization(this BindingBase binding) 
    { 
     var sb = new StringBuilder(); 
     var writer = XmlWriter.Create(sb, new XmlWriterSettings 
     { 
      Indent = true, 
      ConformanceLevel = ConformanceLevel.Fragment, 
      OmitXmlDeclaration = true, 
      NamespaceHandling = NamespaceHandling.OmitDuplicates, 
     }); 
     var mgr = new XamlDesignerSerializationManager(writer); 

     // HERE BE MAGIC!!! 
     mgr.XamlWriterMode = XamlWriterMode.Expression; 
     // THERE WERE MAGIC!!! 

     System.Windows.Markup.XamlWriter.Save(binding, mgr); 
     StringReader stringReader = new StringReader(sb.ToString()); 
     XmlReader xmlReader = XmlReader.Create(stringReader); 
     object newBinding = (object)XamlReader.Load(xmlReader); 
     if (newBinding == null) 
     { 
      throw new ArgumentNullException("Binding could not be cloned via Xaml Serialization Stack."); 
     } 

     if (newBinding is Binding) 
     { 
      return (Binding)newBinding; 
     } 
     else if (newBinding is MultiBinding) 
     { 
      return (MultiBinding)newBinding; 
     } 
     else if (newBinding is PriorityBinding) 
     { 
      return (PriorityBinding)newBinding; 
     } 
     else 
     { 
      throw new InvalidOperationException("Binding could not be cast."); 
     } 
    } 
}