AFAIK, TField.OnChange is normaly only fired when we code "aField.Asxxx:= ..." (without CachedUpdate). So, without CachedUpdate, if you Cancel afterwards "aField.Asxxx:= ...", called in one way or another, this event will not be fired. In other words, what you observe - with CachedUpdate enabled - doesn't surprise me at all.
A normal Cancel can be seen as a [ Rollback + Refresh SQL statement ]. With the CachedUpdate layer (=~ fake temporary database, buffered on client side, over\before TDataset itself), a CancelUpdate should be coded using another new memory buffer (CachedUpdate = " briefcase \ travel-case model ", a kind of " offline database pattern ") on top, over the TDataset and its layer of TFields (really connected, ultimately through a TUpdateSQL polymorphism and its Apply methods, to the real database).