How can you clone a WPF object?

本秂侑毒 提交于 2019-12-17 02:33:10

问题


Anybody have a good example how to deep clone a WPF object, preserving databindings?


The marked answer is the first part.

The second part is that you have to create an ExpressionConverter and inject it into the serialization process. Details for this are here:
http://www.codeproject.com/KB/WPF/xamlwriterandbinding.aspx?fid=1428301&df=90&mpp=25&noise=3&sort=Position&view=Quick&select=2801571


回答1:


The simplest way that I've done it is to use a XamlWriter to save the WPF object as a string. The Save method will serialize the object and all of its children in the logical tree. Now you can create a new object and load it with a XamlReader.

ex: Write the object to xaml (let's say the object was a Grid control):

string gridXaml = XamlWriter.Save(myGrid);

Load it into a new object:

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



回答2:


In .NET 4.0, the new xaml serialization stack makes this MUCH easier.

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



回答3:


There are some great answers here. Very helpful. I had tried various approaches for copying Binding information, including the approach outlined in http://pjlcon.wordpress.com/2011/01/14/change-a-wpf-binding-from-sync-to-async-programatically/ but the information here is the best on the Internet!

I created a re-usable extension method for dealing with InvalidOperationException “Binding cannot be changed after it has been used.” In my scenario, I was maintaining some code somebody wrote, and after a major DevExpress DXGrid framework upgrade, it no longer worked. The following solved my problem perfectly. The part of the code where I return the object could be nicer, and I will re-factor that later.

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



回答4:


How about:

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

Of course this deep clones any object, and it might not be the fastest solution in town, but it has the least maintenance... :)



来源:https://stackoverflow.com/questions/32541/how-can-you-clone-a-wpf-object

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!