There are two parts to this. Events for change notification are one piece, but maintaining history is another important piece. Entity Framework does this too (as does LINQ to SQL), and I've implemented this in my own code as well. At minimum, you keep a flag for a member to say that it has changed. Depending on your requirements, you may keep the original value as well. This usually becomes the task of a separate object. Entity Framework keeps its change tracking in a separate object (EntityState, if I remember correctly).
In my own code, I developed a "DataMember" class that not only held the values, but also kept change flag, null status, and various other useful things. These DataMembers were private members in an Entity class, and the Entity provided properties that exposed the data as simple data types. The property get and set methods interacted with the DataMember to "do the right thing", but the DataMember did change tracking. My Entity class inherited from an "EntityBase" class that provided methods to check for change at the entity level, accept changes (reset change flags), etc. Adding change notification will be the next thing I do, but having a DataMember class for individual data elements, and an EntityBase to own the change notification event handler, will simplify this a lot.
EDITED TO ADD:
Now that I'm at work, I can add some code samples. Here's the interface definition for my DataMember class:
public interface IDataMember<T> : IDataMember
{
T Value { get; set; }
T Get();
void Set(T value);
}
public interface IDataMember
{
string FieldName { get; set; }
string OracleName { get; set; }
Type MemberType { get; }
bool HasValue { get; set; }
bool Changed { get; set; }
bool NotNull { get; set; }
bool PrimaryKey { get; set; }
bool AutoIdentity { get; set; }
EntityBase Entity { get; set;}
object GetObjectValue();
void SetNull();
}
Here's a typical property in an entity class:
private DataMember<bool> m_Monday;
public bool? Monday
{
get
{
if (m_Monday.HasValue)
return m_Monday.Get();
else
return null;
}
set
{
if (value.HasValue)
m_Monday.Set(value.Value);
else
m_Monday.SetNull();
}
}
Note that the DataMember can support properties as nullable, or not.
Constructor code to add a DataMember:
m_Monday = new DataMember<bool>("Monday");
Members.Add(m_Monday);