При разработке приложений часто встречается следующий сценарий: имеется некоторый набор данных доступных для просмотра и редактирования, например, это могут быть бизнес-сущности или настройки приложения. В момент, когда пользователь решает что-либо отредактировать, ему обычно становится доступна специальная форма с нужными полями ввода-вывода и другими элементами управления. Если он вносит какие-либо корректировки в данные, то при обработке формы хорошим тоном является запрос-подтверждение перед окончательным применением внесённых правок. В случае согласия пользователя данные обновляются в источнике и на интерфейсе, а при отмене используются старые значения.
Данная задача включает две подзадачи:
1) когда пользователь уходит с формы редактирования, необходимо понимать, действительно ли он произвёл изменения, чтобы не задавать вопрос на подтверждение впустую и не перезаписывать идентичные данные;
2) если редактированию подвергается непосредственно исходная сущность, а не её копия, то в случае отмены необходимо сохранять возможность отката к исходным значениям.
В статье мы рассмотрим обобщённый и очень лаконичный [размером в несколько строк кода!] подход к решению подобного рода задач, основанный на использовании библиотеки Replication Framework.

Рассмотрим пример приложения. Пусть дан список сущностей, среди которых пользователь может выбрать любую и нажать на кнопку редактирования [в режиме оригинала либо копии].

В режиме редактирования оригинала при изменении сущности в диалоговом окне соответствующие значения немедленно обновляются и в главном, чего не происходит в режиме копии.

После подтверждения изменений выводится список всех найденных различий, если поднят флаг Show detailed changes, либо просто выводится сообщение об обнаружении хотя бы одного отличия [в реальных ситуациях иногда достаточно и такого поведения].

При отмене используются старые значения.

Теперь взглянем на код метода, который отвечает за данное поведение.
Как видим, метод достаточно обобщённый и его можно испольовать для сущностей других типов.
Теперь обратим внимание на ключевые моменты. Работа библиотеки Replication Framework основана на использовании мгновенных снимков объектов в произвольные моменты времени, то есть с помощью метода-расширения Snapshot можно запросто сделать хронику мутаций [историю изменений] произвольного объекта или графа.
Далее можно сопоставить два снимка, чтобы выявить различия в состоянии графа между двумя любыми контрольными точками.
С помощью вызова метода ReplicateGraph можно воссоздать новую копию графа идентичную той, что зафиксирована на снимке, а с помощью ReconstructGraph при наличии кэша репликации совершить реконструкцию графа, то есть вернуть старый экземпляр к прежнему состоянию.
Более подробную информацию об использовании библиотеки вы можете найти в предыдущих публикациях:
1) Replication Framework • глубинное копирование и обобщённое сравнение связных графов объектов
2) Обобщённое копирование связных графов объектов в C# и нюансы их сериализации
Библиотека является бесплатной для некоммерческих и учебных проектов, а на Nuget доступна пробная версия, которая функциональна до конца лета. Для получения лицензионной версии с неограниченным сроком действия и доступа к исходным кодам необходимо отправить запрос на адрес makeman@tut.by.
За внешней простотой использования и хорошей функциональностью библиотеки кроется большая и кропотливая работа по её созданию и отладке, поэтому любая материальная поддержка и покупка коммерческой лицензии очень приветсвуются!
Вдохновения тебе, читатель!
Данная задача включает две подзадачи:
1) когда пользователь уходит с формы редактирования, необходимо понимать, действительно ли он произвёл изменения, чтобы не задавать вопрос на подтверждение впустую и не перезаписывать идентичные данные;
2) если редактированию подвергается непосредственно исходная сущность, а не её копия, то в случае отмены необходимо сохранять возможность отката к исходным значениям.
В статье мы рассмотрим обобщённый и очень лаконичный [размером в несколько строк кода!] подход к решению подобного рода задач, основанный на использовании библиотеки Replication Framework.

Рассмотрим пример приложения. Пусть дан список сущностей, среди которых пользователь может выбрать любую и нажать на кнопку редактирования [в режиме оригинала либо копии].

В режиме редактирования оригинала при изменении сущности в диалоговом окне соответствующие значения немедленно обновляются и в главном, чего не происходит в режиме копии.

После подтверждения изменений выводится список всех найденных различий, если поднят флаг Show detailed changes, либо просто выводится сообщение об обнаружении хотя бы одного отличия [в реальных ситуациях иногда достаточно и такого поведения].

При отмене используются старые значения.

Теперь взглянем на код метода, который отвечает за данное поведение.
private void Edit<T>(T sourceEntry, bool useCopy, bool showChanges, ReplicationProfile replicationProfile) { var cache = new ReconstructionCache(); var sourceSnapshot = sourceEntry.CreateSnapshot(cache, replicationProfile); var editableEntry = useCopy ? sourceSnapshot.ReplicateGraph() : sourceEntry; if (GetView(editableEntry).ShowDialog() == true) { var resultSnapshot = editableEntry.CreateSnapshot(null, replicationProfile); var changes = sourceSnapshot.Juxtapose(resultSnapshot) .Where(j => j.State != Etalon.State.Identical); if (changes.Any()) { MessageBox.Show(showChanges ? changes.Aggregate("", (x, y) => x + y + Environment.NewLine) : "Any changes has been detected!"); UpdateSourceData(editableEntry); UpdateUserInterface(); } else MessageBox.Show("There are no any changes."); } else if (!useCopy) sourceSnapshot.ReconstructGraph(cache); }
Сущность Person
public class Person : INotifyPropertyChanged { private int _id; private string _name; private string _birthday; private string _phone; private string _mail; public event PropertyChangedEventHandler PropertyChanged = (o, e) => { }; private void Set<T>(ref T target, T value, [CallerMemberName]string caller = "") { if (Equals(target, value)) return; target = value; PropertyChanged(this, new PropertyChangedEventArgs(caller)); } public int Id { get => _id; set => Set(ref _id, value); } public string Name { get => _name; set => Set(ref _name, value); } public string Birthday { get => _birthday; set => Set(ref _birthday, value); } public string Phone { get => _phone; set => Set(ref _phone, value); } public string Mail { get => _mail; set => Set(ref _mail, value); } }
Профиль репликации для сущности Person
private static readonly ReplicationProfile PersonRepicationProfile = new ReplicationProfile { MemberProviders = new List<MemberProvider> { new CoreMemberProviderForKeyValuePair(), new CoreMemberProvider(BindingFlags.Public | BindingFlags.Instance, Member.CanReadWrite), } };
Как видим, метод достаточно обобщённый и его можно испольовать для сущностей других типов.
Теперь обратим внимание на ключевые моменты. Работа библиотеки Replication Framework основана на использовании мгновенных снимков объектов в произвольные моменты времени, то есть с помощью метода-расширения Snapshot можно запросто сделать хронику мутаций [историю изменений] произвольного объекта или графа.
var cache = new ReconstructionCache(); var sourceSnapshot = sourceEntry.CreateSnapshot(cache, replicationProfile); ... var resultSnapshot = editableEntry.CreateSnapshot(null, replicationProfile);
Далее можно сопоставить два снимка, чтобы выявить различия в состоянии графа между двумя любыми контрольными точками.
var changes = sourceSnapshot.Juxtapose(resultSnapshot) .Where(j => j.State != Etalon.State.Identical);
С помощью вызова метода ReplicateGraph можно воссоздать новую копию графа идентичную той, что зафиксирована на снимке, а с помощью ReconstructGraph при наличии кэша репликации совершить реконструкцию графа, то есть вернуть старый экземпляр к прежнему состоянию.
var editableEntry = useCopy ? sourceSnapshot.ReplicateGraph() : sourceEntry;
var cache = new ReconstructionCache(); var sourceSnapshot = sourceEntry.CreateSnapshot(cache, replicationProfile); ... else if (!useCopy) sourceSnapshot.ReconstructGraph(cache);
Более подробную информацию об использовании библиотеки вы можете найти в предыдущих публикациях:
1) Replication Framework • глубинное копирование и обобщённое сравнение связных графов объектов
2) Обобщённое копирование связных графов объектов в C# и нюансы их сериализации
Библиотека является бесплатной для некоммерческих и учебных проектов, а на Nuget доступна пробная версия, которая функциональна до конца лета. Для получения лицензионной версии с неограниченным сроком действия и доступа к исходным кодам необходимо отправить запрос на адрес makeman@tut.by.
За внешней простотой использования и хорошей функциональностью библиотеки кроется большая и кропотливая работа по её созданию и отладке, поэтому любая материальная поддержка и покупка коммерческой лицензии очень приветсвуются!
Вдохновения тебе, читатель!
