NOTE: This is an old blog post that I obviously never posted. I wanted to send a link to this article to someone and when searching through my archives I realized I never posted it! Enjoy.
Because of architecture restrictions (too difficult to explain in a few sentences), I had a situation where an ASP.NET implementation had to let the client execute a function and return the results for display in ASP.NET. I originally considered a smart-client application with no-touch-deployment since all clients will have the .NET framework, but the application UI had to be in ASP.NET. So I decided to use a WinForms User Control hosted in Internet Explorer.
No amount of tweaks and hacks would capture the event I raised in the .NET user control. I did some digging and found a couple of newsgroup postings as well as an MSDN article detailing the steps necessary to get a UserControl hosted in IE to raise events properly. It comes down to needing old, COM-style event source sinks. I can't give you a full explanation on this since but you'll find a nice deep article about it on MSDN. However, a little refactoring and a few attributes got me what I needed.
First, you need to define an Interface that contains the names and signature of the events you want to expose. The interface needs two attributes:
1) InterfaceType(ComInterfaceType.InterfaceIsIDispatch) -- define an IDispatch interface
2) Guid(...) -- define a GUID for the interface
In addition, each method in the interface needs a DispId() attribute with a unique value applied to it. Here's a sample interface for an event called "InfoMessage":
public interface IClientControlEvents
void InfoMessage(string message);
Now, to hook this into the UserControl, you need to add two attributes to your class:
1) ClassInterface(ClassInterfaceType.None) -- Prevent .NET from generating a default interface for this class.
2) ComSourceInterfaces(typeof(IClientControlEvents)) -- Define the interface for COM event source sinks
All that's left is to use the regular .NET delegate/event mechanism for event handling. Just make sure the event name matches the name defined in the interface:
public delegate void InfoMessageEventHandler(string data);
public event InfoMessageEventHandler InfoMessage;
<object id="myControl" classid="samplecontrol.dll#MyNamespace.ClientControl" />
The only other thing to watch out for is that any public methods you want to call through script need to be done via an interface implemented by your UserControl.