Pregunta

¿Alguien tiene un buen ejemplo de cómo realizar una clonación profunda de un objeto WPF, preservando los enlaces de datos?


La respuesta marcada es la primera parte.

La segunda parte es que debes crear un ExpressionConverter e inyectarlo en el proceso de serialización.Los detalles para esto están aquí:
http://www.codeproject.com/KB/WPF/xamlwriterandbinding.aspx?fid=1428301&df=90&mpp=25&noise=3&sort=Position&view=Quick&select=2801571

¿Fue útil?

Solución

La forma más sencilla que lo he hecho es usar XamlWriter para guardar el objeto WPF como una cadena.El método Save serializará el objeto y todos sus hijos en el árbol lógico.Ahora puede crear un nuevo objeto y cargarlo con XamlReader.

ex:Escriba el objeto en xaml (digamos que el objeto era un control Grid):

string gridXaml = XamlWriter.Save(myGrid);

Cárgalo en un nuevo objeto:

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

Otros consejos

En .NET 4.0, la nueva pila de serialización xaml hace que esto sea MUCHO más 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();

Hay algunas respuestas excelentes aquí.Muy útil.Había probado varios métodos para copiar información vinculante, incluido el método descrito en http://pjlcon.wordpress.com/2011/01/14/change-a-wpf-binding-from-sync-to-async-programatically/ ¡pero la información aquí es la mejor en Internet!

Creé un método de extensión reutilizable para lidiar con InvalioperationException "La unión no se puede cambiar después de que se haya utilizado". En mi escenario, estaba manteniendo algún código que alguien escribió, y después de una importante actualización del marco DXGRID DXGRID, ya no funcionó.Lo siguiente resolvió mi problema perfectamente.La parte del código donde devuelvo el objeto podría ser mejor y la refactorizaré más adelante.

/// <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.");
        }
    }
}

Qué tal si:

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

Por supuesto, esto clona profundamente cualquier objeto, y puede que no sea la solución más rápida que existe, pero tiene el menor mantenimiento...:)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top