Как можно клонировать объект WPF?

У кого-нибудь есть хороший пример, как глубоко клонировать объект WPF, сохраняя привязки данных?


Отмеченный ответ - первая часть.

Вторая часть заключается в том, что вам нужно создать ExpressionConverter и внедрить его в процесс сериализации. Подробности здесь:
http://www.codeproject.com/KB/WPF/xamlwriterandbinding.aspx?fid=1428301&df=90&mpp=25&noise=3&sort=Position&view=Quick&select=2801571

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
40
0
43 887
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Как насчет:

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

Конечно, это глубокое клонирование любого объекта, и, возможно, это не самое быстрое решение в городе, но оно требует минимального обслуживания ... :)

Ответ принят как подходящий

Самый простой способ, который я сделал, - использовать XamlWriter для сохранения объекта WPF в виде строки. Метод Save сериализует объект и все его дочерние элементы в логическом дереве. Теперь вы можете создать новый объект и загрузить его с помощью XamlReader.

бывший: Запишите объект в xaml (скажем, объект был элементом управления Grid):

string gridXaml = XamlWriter.Save(myGrid);

Загрузите его в новый объект:

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

Имейте в виду, что он также клонирует имя, что усложняет их использование для элементов пользовательского интерфейса, если они должны быть размещены в одном корневом контейнере.

toad 28.04.2009 20:17

Я не думаю, что это сохраняет анимацию, не так ли?

Erich Mirabal 29.04.2009 15:52

Чтобы было ясно, это только половина решения (как это было в 08). Это приведет к оценке привязок и сериализации результатов. Если вы хотите сохранить привязки (как заданный вопрос), вы должны либо добавить ExpressionConverter к типу привязки во время выполнения (см. Вторую часть моего вопроса для соответствующей ссылки), либо увидеть мой собственный ответ ниже, чтобы узнать, как это сделать в 4.0 .

user1228 10.03.2011 17:13

Удивительно просто идеально :)

Ahmed Mahmoud 13.05.2015 04:31

Жаль, что XamlWriter такой медленный. Жаль, что не было альтернативы.

willem 09.02.2016 11:22

не работает с элементами управления, использующими привязку к универсальным типам.

Henka Programmer 30.05.2017 14:12

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

Я не понимаю, чем это отличается от простого использования XamlWriter.Save? По крайней мере, я не увидел других результатов при попытке сериализовать DataGrid.

JP Richardson 09.03.2011 20:27

@JP извините, не все так ясно .... Вопрос был в том, как клонировать сохраняя привязки. Отмеченный ответ наполовину правильный; фактически, если вы это сделаете, вы обнаружите, что ваши привязки будут оценены, и результаты (а не сами привязки) будут сериализованы. В моем вопросе я добавил к решению вторую половину, а именно: добавить ExpressionConverter и добавить его к типу привязки во время выполнения. Это немного непонятно. То же самое можно сделать с помощью этого ответа - см. Комментарий HERE BE MAGIC? Это указывает сериализатору нет оценивать привязки при сериализации. Аккуратный.

user1228 10.03.2011 17:11

Я видел это. Я все еще работаю над той же проблемой с моим Datagrid и не заметил другого результата в отношении привязки данных. Мой Datagrid все еще пуст. Я, должно быть, упускаю что-то еще. Тем не менее, я дам вам голос за то, что вы указали на все это.

JP Richardson 10.03.2011 23:28

@JPRichardson: сериализуйте текст и проверьте результат, чтобы увидеть, сохранены ли {Binding}.

user1228 11.03.2011 00:20

Я продаю его как полезный, я пишу форму динамического ввода данных, и это решило мою проблему привязки. Спасибо.

Masoud 16.07.2013 12:35

Здесь есть отличные ответы. Очень полезно. Я пробовал различные подходы для копирования информации о привязке, включая подход, описанный в http://pjlcon.wordpress.com/2011/01/14/change-a-wpf-binding-from-sync-to-async-programatic/, но информация здесь лучшая в Интернете!

Я создал многократно используемый метод расширения для работы с 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.");
        }
    }
}

Другие вопросы по теме