Of course most of us simply make use of predefined events but there has been a change in the way that this works. Originally we needed a delegate type for each even slightly different even or we just passed object types to allow the event handler to work with a range of types. A better solution is to use generics and this is the approach now taken by the framework classes.
For example, the original standard event handler was no generic:
public delegate void EventHandler( object sender, EventArgs e);
Using object as the first parameter allowed any class to raise the event and still notify the users of the event handlers what had raised the event. The new generic version is:
public delegate void EventHandler<TEventArgs> (object sender, TEventArgs e) where TEventArgs : EventArgs;
which still leaves the sender untyped. A better version is:
public delegate void GenericEventHandler<S,A> (S sender,A args);
In this case the event would be set up using something like:
public event GenericEventHandler <MyClass,MyArgs> MyNewEvent;
Generics significantly simplify the implementation of events and by reducing the need to pass an object type increase overall type safety.