Клонирование элементов управления WPF и иерархий объектов - PullRequest
2 голосов
/ 20 июля 2011

У меня проблемы с клонированием иерархии объектов.Это набор инструментов для моделирования приложений, набор инструментов содержит экземпляры классов в качестве прототипов.Но мне нелегко их клонировать:)

Следующий код показывает проблему:

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 в базовых классах) и двоичную сериализацию (BinaryFormatter и MemoryStreams).

В первом подходе отсутствует способ вызова base.clone() метод (или я не прав?), Последний не работает, потому что UIElement s не [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!
  }
}

Ответы [ 3 ]

6 голосов
/ 21 сентября 2012

А вот и функция для него:

    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 голосов
/ 20 июля 2011

Если вы пытаетесь клонировать элементы UIE, используйте XamlWriter для сохранения в строку, хотя ни один метод клонирования не является надежным. Затем вы используете XamlReader для загрузки копии. Вы все еще можете столкнуться с проблемами. Такие вещи, как обработчики, которые не копируются, x: дублирование имени и т. Д. Но для простых элементов, таких как Grid или Brush, это прекрасно работает.

Редактировать 1: Не существует общего способа клонирования чего-либо, однако:

1) Если функция клона написана правильно, она вызовет для вас базовый клон и скопирует содержимое базового класса. Если он написан неправильно, вызов базового Clone не сильно поможет, хотя вы можете вызвать приватный метод таким образом .

2) Если вам нужно, вы можете использовать Reflection, чтобы скопировать почти все, даже обработчики щелчков, из старого объекта в новый.

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;
}
0 голосов
/ 20 июля 2011

Сам не пробовал, но XamlWriter выглядит многообещающе.

...