40 votes

Comment pouvez-vous cloner un objet WPF?

Quelqu'un a un bon exemple de la façon de profondeur cloner un objet WPF, la préservation de databindings?


La forte réponse est la première partie.

La seconde partie est que vous devez créer un ExpressionConverter et à l'injecter dans le processus de sérialisation. Les détails de ce sont ici:
http://www.codeproject.com/KB/WPF/xamlwriterandbinding.aspx?fid=1428301&df=90&mpp=25&noise=3&sort=Position&view=Quick&select=2801571

64voto

Alan Le Points 3375

Le moyen le plus simple que j'ai fait est d'utiliser un XamlWriter pour enregistrer l'objet WPF en tant que chaîne. La méthode Save sérialise l'objet et tous ses enfants dans l'arborescence logique. Vous pouvez maintenant créer un nouvel objet et le charger avec un XamlReader.

ex: écrire l'objet dans xaml (disons que l'objet était un contrôle Grid):

 string gridXaml = XamlWriter.Save(myGrid);
 

Chargez-le dans un nouvel objet:

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

36voto

Will Points 76760

Dans .NET 4.0, la nouvelle pile de sérialisation xaml rend cela BEAUCOUP plus facile.

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

5voto

John Zabroski Points 372

Il y a quelques grandes réponses ici. Très utile. J'avais essayé différentes approches pour la copie des informations de Liaison, y compris l'approche décrite dans http://pjlcon.wordpress.com/2011/01/14/change-a-wpf-binding-from-sync-to-async-programatically/ mais l'information ici est le meilleur sur Internet!

J'ai créé un ré-utilisable de la méthode d'extension pour traiter InvalidOperationException "Liaison ne peut pas être changé après qu'il a été utilisé." Dans mon scénario, j'ai été le maintien du code quelqu'un a écrit, et après une importante DevExpress DXGrid cadre de la mise à niveau, il ne travaillait plus. Le suivant a résolu mon problème à la perfection. La partie du code où je retourne l'objet pourrait être plus agréable, et je vais re-facteur que plus tard.

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

0voto

Arcturus Points 14366

Que diriez-vous:

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

Bien sûr, cette profondeur clone n'importe quel objet, et ce n'est peut-être pas la solution la plus rapide en ville, mais elle a le moins d'entretien ... :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X