Como você pode clonar um object WPF?

Alguém tem um bom exemplo de como clonar profundamente um object WPF, preservando as conexões de dados?


A resposta marcada é a primeira parte.

A segunda parte é que você tem que criar um ExpressionConverter e injetá-lo no processo de serialização. Detalhes para isso estão aqui:
http://www.codeproject.com/KB/WPF/xamlwriterandbinding.aspx?fid=1428301&df=90&mpp=25&noise=3&sort=Position&view=Quick&select=2801571

A maneira mais simples que eu fiz isso é usar um XamlWriter para salvar o object WPF como uma seqüência de caracteres. O método Save serializará o object e todos os seus filhos na tree lógica. Agora você pode criar um novo object e carregá-lo com um XamlReader.

ex: Escreva o object para xaml (digamos que o object fosse um controle Grid):

string gridXaml = XamlWriter.Save(myGrid); 

Carregue em um novo object:

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

No .NET 4.0, a nova pilha de serialização xaml torna isso muito mais fácil.

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

Existem algumas ótimas respostas aqui. Muito útil. Eu tentei várias abordagens para copiar informações vinculativas, incluindo a abordagem descrita em http://pjlcon.wordpress.com/2011/01/14/change-a-wpf-binding-from-sync-to-async-programtically/ mas as informações aqui são as melhores da internet!

Eu criei um método de extensão reutilizável para lidar com InvalidOperationException “A binding não pode ser alterada depois que foi usada.” No meu cenário, eu estava mantendo algum código que alguém escreveu, e depois de uma grande atualização da estrutura DevExpress DXGrid, não funcionava mais. O seguinte resolveu meu problema perfeitamente. A parte do código onde eu retorno o object poderia ser mais agradável, e eu refaço isso mais tarde.

 ///  /// Extension methods for the WPF Binding class. ///  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."); } } } 

E se:

  public static T DeepClone(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; } } 

Claro que este clone profundo de qualquer object, e pode não ser a solução mais rápida na cidade, mas tem menos manutenção … 🙂