40 Stimmen

Wie kann man ein WPF-Objekt klonen?

Hat jemand ein gutes Beispiel, wie man ein WPF-Objekt tief klonen kann, wobei Datenbindungen erhalten bleiben?


Die markierte Antwort ist der erste Teil.

Der zweite Teil besteht darin, einen ExpressionConverter zu erstellen und ihn in den Serialisierungsprozess einzufügen. Details dazu finden Sie hier:
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 Punkte 8273

Der einfachste Weg, den ich gemacht habe, ist die Verwendung eines XamlWriter, um das WPF-Objekt als Zeichenfolge zu speichern. Die Save-Methode serialisiert das Objekt und alle seine Kinder im logischen Baum. Jetzt können Sie ein neues Objekt erstellen und es mit einem XamlReader laden.

z.B .: Schreiben Sie das Objekt in XAML (nehmen wir an, das Objekt war ein Grid-Control):

string gridXaml = XamlWriter.Save(myGrid);

Laden Sie es in ein neues Objekt:

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

37voto

In .NET 4.0 macht der neue XAML Serialisierungs-Stack dies VIEL einfacher.

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

// HIER SEI MAGIE!!!
mgr.XamlWriterMode = XamlWriterMode.Expression;
// DA WAR MAGIE!!!

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

5voto

John Zabroski Punkte 1995

Es gibt hier einige großartige Antworten. Sehr hilfreich. Ich hatte verschiedene Ansätze zum Kopieren von Binding-Informationen ausprobiert, einschließlich des im http://pjlcon.wordpress.com/2011/01/14/change-a-wpf-binding-from-sync-to-async-programatically/ skizzierten Ansatzes, aber die Informationen hier sind die besten im Internet!

Ich habe eine wiederverwendbare Erweiterungsmethode erstellt, um mit der InvalidOperationException "Binding kann nach Verwendung nicht geändert werden" umzugehen. In meinem Szenario habe ich den Code von jemandem gewartet, und nach einem großen Upgrade des DevExpress DXGrid-Frameworks hat es nicht mehr funktioniert. Das Folgende hat mein Problem perfekt gelöst. Der Teil des Codes, in dem ich das Objekt zurückgebe, könnte besser sein, und ich werde das später refaktorisieren.

/// 
/// Erweiterungsmethoden für die WPF-Binding-Klasse.
/// 
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);

        // HIER LIEGT DER ZAUBER!!!
        mgr.XamlWriterMode = XamlWriterMode.Expression;
        // DA WAR DER ZAUBER!!!

        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 konnte nicht über die Xaml-Serialisierungsstack geklont werden.");
        }

        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 konnte nicht umgewandelt werden.");
        }
    }
}

0voto

Arcturus Punkte 26057

Wie wäre es mit:

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

Natürlich klonen Sie damit jedes Objekt tief und es ist möglicherweise nicht die schnellste Lösung in der Stadt, aber es erfordert am wenigsten Wartung... :)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X