C# 如何克隆 WPF 对象?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32541/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 09:12:13  来源:igfitidea点击:

How can you clone a WPF object?

提问by

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

任何人都有一个很好的例子,如何深度克隆 WPF 对象,保留数据绑定?



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

第二部分是您必须创建一个 ExpressionConverter 并将其注入序列化过程。详细信息在这里:http: //www.codeproject.com/KB/WPF/xamlwriterandbinding.aspx?fid=1428301& df=90& mpp=25&noise=3&sort=Position& view=Quick&
select=2801571

采纳答案by Alan Le

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.

我所做的最简单的方法是使用 XamlWriter 将 WPF 对象保存为字符串。Save 方法将序列化逻辑树中的对象及其所有子项。现在您可以创建一个新对象并使用 XamlReader 加载它。

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

例如:将对象写入 xaml(假设该对象是一个 Grid 控件):

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

回答by Arcturus

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... :)

当然,这种深度克隆任何对象,它可能不是镇上最快的解决方案,但它的维护最少...... :)

回答by Alan Le

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

在 .NET 4.0 中,新的 xaml 序列化堆栈使这变得更加容易。

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

回答by John Zabroski

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!

这里有一些很好的答案。很有帮助。我尝试了各种复制绑定信息的方法,包括http://pjlcon.wordpress.com/2011/01/14/change-a-wpf-binding-from-sync-to-async-programatically/ 中概述的方法,但是这里的信息是互联网上最好的!

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.

我创建了一个可重用的扩展方法来处理 InvalidOperationException “绑定使用后无法更改”。在我的场景中,我正在维护一些某人编写的代码,在一次主要的 DevExpress DXGrid 框架升级之后,它不再起作用。以下完美解决了我的问题。我返回对象的代码部分可能会更好,稍后我将重新考虑它。

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