Un enfoque no ortodoxo podría estar utilizando un marco AOP como PostSharp para "tejer" un controlador antes/después de llamar al descriptor, que desencadena un evento.
Crea una clase externa que contiene el código de manejo previo y/o posterior para cuando se accede a su propiedad, verifica si el valor de la propiedad cambió entre pre y post, y genera un evento.
Tenga en cuenta que al tomar el valor de comparación (dentro del código del controlador), puede entrar en un bucle infinito (llame al acceso de propiedad, que llama al manejador AOP, que llama al dispositivo de acceso, etc.), por lo que es posible que deba reflejar en la clase que contiene esta propiedad para obtener el campo de respaldo.
Eso es .NET 1.1 :) Como Marc Gravell dijo ... mucho trabajo, poco beneficio. –