Sounds like you want state management combined with property change notifications. The state management is really up to you to with how you want to do it. The few concepts that make sense are to use either a backup copy of the object or a Dictionary<string, object>
that maps the original properties (property name) to underlying fields (property values).
As for determining if there are any changes, I would utilize the INotifyPropertyChanged interface. This would keep state management and notifications internal to the class. Just implement a wrapper (good practice) called OnPropertyChanged(string propName, object propValue) that sets a boolean array/dictionary (Dict<string, bool>
) that would then set whether there are any changes, with a HasChanges property returning true if any properties are changed. Example class:
public class TestClass : INotifyPropertyChanged
{
private Dictionary<string, object> BackingStore = new Dictionary<string,object>();
private Dictionary<string, bool> Changes = new Dictionary<string, bool>();
private string _testString;
public string TestString
{
get { return _testString; }
set { _testString = value; OnPropertyChanged("TestString", value); }
}
private bool HasChanges { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public TestClass(string value)
{
_testString = value;
SaveValues();
}
public void SaveValues()
{
// Expensive, to use reflection, especially if LOTS of objects are going to be used.
// You can use straight properties here if you want, this is just the lazy mans way.
this.GetType().GetProperties().ToList().ForEach(tProp => { BackingStore[tProp.Name] = tProp.GetValue(this, null); Changes[tProp.Name] = false; });
HasChanges = false;
}
public void RevertValues()
{
// Again, you can use straight properties here if you want. Since this is using Property setters, will take care of Changes dictionary.
this.GetType().GetProperties().ToList().ForEach(tProp => tProp.SetValue(this, BackingStore[tProp.Name], null));
HasChanges = false;
}
private void OnPropertyChanged(string propName, object propValue)
{
// If you have any object types, make sure Equals is properly defined to check for correct uniqueness.
Changes[propName] = BackingStore[propName].Equals(propValue);
HasChanges = Changes.Values.Any(tr => tr);
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
For simplicity sake, I just use SaveValues/RevertValues to save/undo changes. However, those can easily be used to implement the IEditableObject
interface (BeginEdit, CancelEdit, EndEdit). The PropertyChanged event can then be subscribed to by whatever form the objects are being bound in (or even to an underlying BindingList, that way only a single instance needs to be subscribed to), which checks for the HasChanges flag and sets the appropriate state of the form.