Może Ci się przyda, klasa robi kopię binarną obiektu i umożliwia również przywrócenie oryginału.
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Windows;
namespace Tempus.Data
{
/// <summary>
/// Klasa umożliwiająca przed rozpoczęciem edycji wykonanie binarnej kopii obiektu.
/// Ale co ważniejsze - udostępnia przywrócenie danych w przypadku anulowania operacji.
/// </summary>
public class EditableData<T> : IEditableObject, INotifyPropertyChanged where T : class
{
private byte[] _copy;
private T _currentValue;
private bool _hasConflict;
private bool _isEdited;
public void BeginEdit()
{
_isEdited = true;
using (var ms = new MemoryStream())
{
new DataContractSerializer(typeof (T)).WriteObject(ms, this);
_copy = ms.ToArray();
}
}
public void EndEdit()
{
_isEdited = false;
}
public void CancelEdit()
{
_isEdited = false;
// Jeśli w czasie edycji dane zostały zmienione przez innego użytkownika ustaw je jako aktualne.
if (_hasConflict)
{
SetValues(_currentValue);
_currentValue = null;
_hasConflict = false;
return;
}
// Jeżeli nie ma zmian zakończ.
if (!HasChanges()) return;
// Przywróć stan obiektu sprzed edycji.
using (var ms = new MemoryStream(_copy))
{
var original = (T) new DataContractSerializer(typeof (T)).ReadObject(ms);
SetValues(original);
}
}
public event PropertyChangedEventHandler PropertyChanged;
public bool HasChanges()
{
using (var ms = new MemoryStream())
{
new DataContractSerializer(typeof (T)).WriteObject(ms, this);
return !ms.ToArray().SequenceEqual(_copy);
}
}
/// <summary>
/// Zaktualizuj obiekt nowymi wartościami.
/// </summary>
public void Update(T current)
{
// Jeśli dane są aktualnie edytowane poinformuj użytkownika o konflikcie i zapamiętaj nowy obiekt.
if (_isEdited)
{
// Todo: zablokuj klawisz zamknij/zapisz.
MessageBox.Show(
"Dane zostały zmienione przez innego użytkownika!\r\n" +
"Zapis zmian został zablokowany.");
_currentValue = current;
_hasConflict = true;
return;
}
SetValues(current);
}
/// <summary>
/// Zastąp bieżące wartości właściwości nowymi.
/// </summary>
private void SetValues(T current)
{
var currentProperties = current.GetType().GetProperties();
var properties = GetType().GetProperties();
foreach (var property in properties)
{
var currentProperty = currentProperties.First(x => x.Name == property.Name);
if (property.CanWrite) property.SetValue(this, currentProperty.GetValue(current, null));
OnPropertyChanged(property.Name);
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
M.