【问题标题】:Cloning WPF controls and object hierarchies克隆 WPF 控件和对象层次结构
【发布时间】:2011-10-09 15:43:42
【问题描述】:

我在克隆对象层次结构时遇到了一些问题。它是一个用于建模应用程序的工具包,该工具箱包含作为原型的类实例。但我很难克隆这些:)

以下代码说明了问题:

public abstract class Shape {
  protected List<UIElement> elements;
  private Canvas canvas;
  ...
  public Canvas getCanvas() { ... };
}

public class MovableShape : Shape {
  protected ... propertyA;
  private ... propertyXY;
  ...
}

public abstract class AbstractLayout : MovableShape, ... {
  ...
}

public class SomeLayoutClass : AbstractLayout, ... {
  ...
}

public class AContainingClass {
  SomeLayoutClass Layout { get; set; }
  ...
}

当我将AContainingClass 的对象插入我的项目工作表时,它应该被克隆。到目前为止,我尝试了手动克隆(由于基类中的 private 字段而失败)和二进制序列化(BinaryFormatterMemoryStreams)。

第一种方法缺少调用base.clone() 方法的方法(或者我错了吗?),后者不起作用,因为UIElements 不是[Serializable]

注意:必须是深拷贝!

有什么想法吗?谢谢!


更新

只是为了澄清我的手动克隆方法: 如果每个类都有自己的Clone方法,如何调用基类的Clone方法?

public class Shape { // not abstract any more
  ...
  public Shape Clone() {
    Shape clone = new Shape() { PropertyA = this.PropertyA, ... };
    ...do some XamlWriter things to clone UIElements...
    return clone;
  }
}

public class MovableShape : Shape {
  ...
  public MovableShape Clone() {
     // how to call base.Clone??? 
     // this would be required because I have no access to the private fields!
  }
}

【问题讨论】:

  • 那么,手动克隆根本不起作用,还是变得笨拙?私人国家不对应公共国家吗?如果它变得笨拙,我建议使用基于反射的代码生成。否则,是否可以选择复制他们的代码来解决这些缺点?图书馆是开源的吗?如果是这样,您可以提交补丁以使对象可克隆。
  • @Merlyn Morgan-Graham:我为手动克隆添加了一个代码示例

标签: c# wpf clone deep-copy


【解决方案1】:

我自己没试过,但XamlWriter 看起来很有希望。

【讨论】:

  • 效果很好,但也不是万无一失(见我的回答)。
【解决方案2】:

这里是它的功能:

    public T XamlClone<T>(T source)
    {
        string savedObject = System.Windows.Markup.XamlWriter.Save(source);

        // Load the XamlObject
        StringReader stringReader = new StringReader(savedObject);
        System.Xml.XmlReader xmlReader = System.Xml.XmlReader.Create(stringReader);
        T target = (T)System.Windows.Markup.XamlReader.Load(xmlReader);

        return target;
    }

【讨论】:

    【解决方案3】:

    如果您尝试克隆 UIElements,请使用 XamlWriter 保存到字符串,尽管没有一种克隆方法是万无一失的。然后使用XamlReader 加载副本。你仍然可能遇到问题。诸如不复制处理程序、复制 x:Name 等。但是对于像 Grid 或 Brush 这样的简单元素,它的效果很好。

    编辑 1: 没有通用的方法来克隆任何东西,但是:

    1) 如果克隆函数编写正确,它会为你调用基类 Clone,并复制基类的东西。如果编写不正确,调用基本克隆将无济于事,但您可以调用私有方法this way

    2) 如果需要,您可以使用反射将几乎所有内容(甚至点击处理程序)从旧对象复制到新对象。

    3) XamlWriter 和 XamlReader 将复制和实例化对象的层次结构,只是减去某些属性。

    编辑 2:这是我在类层次结构中使用的常见克隆设计模式。假设基类形状,派生类圆形:

    protected Circle(Circle t)
    {
        CopyFrom(t);
    }
    
    public override object Clone()
    {
        return new Circle(this);
    }
    
    protected void CopyFrom(Circle t)
    {
        // Ensure we have something to copy which is also not a self-reference
        if (t == null || object.ReferenceEquals(t, this))
            return;
    
        // Base
        base.CopyFrom((Shape)t);
    
        // Derived
        Diameter = t.Diameter;
    }
    

    【讨论】:

    • 我已经更新了我的答案。没有通用的克隆方法,但我提供了更多信息。
    • 谢谢。但是第 1 点)给我带来了问题,我的克隆功能没有按预期工作:) 我不知道如何正确调用 base.clone()
    • 除非您尝试创建基本类型的对象,否则这对您没有帮助。那是你想要做的吗?如果是这样,我编辑了我的答案以包含调用私有方法的链接。
    • 不,我不想创建基类型的对象,但是当应该克隆派生类时,它必须以某种方式调用基类的克隆方法以确保私有字段基类的也被克隆了:/
    • 如果一个类的Clone写错了,调用基类Clone根本没有用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多