In this case the event is oneditingdone I suppose different controls have different types of change events but I try to handle them all through one event procedure. Which is why it’s important to know if the control actually changed..,
And that's probably why you have trouble detecting which of these events did and did not occur. I understand that this is less code to create. This is the temptation to make the program simpler. But that's not always a good idea. The more we want to increase the capabilities (functionality) of the program, the more complex it becomes. It is impossible to go below a certain level of complexity while maintaining its established functionality.
I don't know how you organize your code, but for larger programs (main window, several dialog windows) I avoid placing more program code in form units. Instead, I create classes: a data container, a view class, and a controller class. Sometimes I have several (two or three) containers. Likewise with controllers. It all depends on the complexity of the program (the problem/issue it is supposed to solve). I usually have at least a couple of views. Sometimes these are classes derived from TCustomControl. And sometimes they come from TComponent and are associated with typical controls, e.g. TEdit, TButton, TMemo, etc. Then such a view is coupled with the mentioned controls. Events generated by views (or controls coupled to them) are usually handled by the controller, sometimes also by the container (usually there are few of them).
This allows me to organize and structure the program design. This is simply a practical use of the MVC design pattern. Of course, you need to exercise moderation. Patterns are helpful for more extensive programs. There is no need to use them in small programs.
I have no idea what would be involved in creating a new type of event that uses a function instead of procedure but acts like tnotifyevent. How are events created? Can I create one in my tedit descendant similar to oneditingdone ?
Events are pointers to methods in objects. Your best bet is to look at some existing classes in the library (in this case LCL). I did that.