I'm not saying you're wrong, as you aren't, though there is something we've to live with I think and that's how databinding works. The reason I fire the Changed event the second some field changes and not when the EndEdit method is called, is because of simple binding (i.e. with textboxes): there, EndEdit for the ROW is NEVER called. So if you bind the 10 fields of an entity to 10 textboxes, you won't see changes if I don't fire the changed events directly. (IEditableObject calls BeginEdit twice: once for the entire object and once for the field being edited)
This behavior creates this wicked situation. Because now the academic discussion has to be held: "when is an entity changed?". Is that:
1) when a field's value is different at point T+n from the value it had at point T
or
2) when a field's value is different at point T' from the value it had at point T
1) defines that the change is always later in time but compared to the original. So if I do:
T: load entity E
T+1: SaveFields
T+2: E.Foo = somevalue
T+3: E is now considered changed
T+4: Rollback fields
T+5: E now is considered the same and unchanged as no field has a different value as it had on T
2) defines that the change is always later in time but compared to the previous time spot. So the previous situation differs on T+5:
T: load entity E
T+1: SaveFields
T+2: E.Foo = somevalue
T+3: E is now considered changed
T+4: Rollback fields
T+5: E is still considered changed because T+5 differs from T+4
Now, for editing INSIDE an edit cycle (BeginEdit -> change a value -> EndEdit) 1) is used. Though between 2 edit cycles (initial value is 0, you change it to 1, move on to another row, come back to the cell, change it back to 0) this is equal to 2).
Rolling back fields to a previous save, is that 1) or 2)? You could argue 2), but what if the values are the same? Then it's a 1). Do you want the events in that case? No not likely. But is that possible to find out? Well with 1 SaveFields -> RollbackFields, it is, but with 10 SaveFields in a row, it's not. As the RollbackFields call still might result in changed fields compared with the 2nd SaveFields in the row of 10 times SavedFields.
RollbackFields now fires ALL fieldChanged events and the entity is changed event. And I think that's good. It fires the
EntityContentsChanged event. You can bind to that event. You then know if something is changed. But what you WANT IMHO is that you DON'T get that event in the situation where it's a 1) but I can't do that.
So, a RollbackFields will result in a changed event for the entity, i.e. a 2). Because RollbackFields rolls back the complete Fields object, which contains if the entity was in fact dirty, you can then determine if the entity was changed since the beginning (entity.IsDirty==true) or not (entity.IsDirty==false). I think with these 2 elements you can accomplish what you want.
(oh, and I know that looking at that IsDirty flag could make RollbackFields able to determine if it actually has to fire changed events, but that's not always true, as the IsChanged flags and IsDirty flag can be manipulated in code. )