Welcome to MSDN Blogs Sign in | Join | Help

Exposing Events from managed controls

Earlier we talked about adding properties and methods to a managed control so that the page hosting the control can interact directly with the managed control programmatically.

This time we will add events which is a little bit more difficult.  To really understand how this works, you have to understand the COM event model (Eric Lippert started a series talking about how this works particularly as it relates to script languages here: http://blogs.msdn.com/ericlippert/archive/2005/09/09/463215.aspx). 

At a very high level, COM events work by allowing someone who wants to listen to events to implement an interface where each method on the interface represents an event that could be fired.  The implementation of this COM interface is then provided to the event source which can call any one of the provided methods when an event is "fired".  .NET has built in support for a more flexible event model based on delegates, but it does provide support for COM-style events through the System.Runtime.InteropServices.ComSourceInterfacesAttribute.

To take advantage of this in a control in the browser, we just need to define a COM interface that contains the signature of each event that we want to expose.  It would look something like this:

using System.Runtime.InteropServices;
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)]
public interface ISimpleEvents {
  [DispId(1)]//Each event must have a unique DispId
  void ButtonClicked();
}

The interface has a single method/event "ButtonClicked".

To get our to use this COM event, we just need to add the System.Runtime.InteropServices.ComSourceInterfacesAttribute.

I expanded on the control we had earlier to add a button to the control in the browser which fires a "ButtonClicked" event which is handled by script in the hosting page.

Host.html

<html>
  <head><title>Simple control host</title></head>
<body>
  <H1>Simple control host page</H1>
  <object id=simpleControl width=200 height=200 classid="SimpleControl.dll#SimpleControl"></object>
  <br>
  <a href="javascript:simpleControl.SayHello();">Say Hello</a>
  <br>
  <input type=text id=colorName value="Green"><input type=button onclick="simpleControl.ThemedBackgroundColor=colorName.value">
  <script language=JavaScript>
    function simpleControl::ButtonClicked() {
      alert("Managed button clicked");
    }
  </script>
</body>
</html>

 

SimpleControl.cs

using System;
using System.Drawing;
using System.Security;
using System.Security.Permissions;
using System.Windows.Forms;
using System.Runtime.InteropServices;

[ComSourceInterfaces(typeof(ISimpleEvents))]
public sealed class SimpleControl : Control {
  private Button button1;

  public SimpleControl() {
   this.BackColor = Color.Green;
   button1 = new Button();
   button1.Text = "Click Me!";
   button1.Width= 100;
   button1.Click += new EventHandler(HandleButtonClick);
   Controls.Add(button1);
  }

  private void HandleButtonClick(object sender, EventArgs e) {
    try {
      new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert();
      MethodInvoker h = ButtonClicked;
      if ( null != h) {
        ButtonClicked();
      }
    } catch (Exception ex) {
      MessageBox.Show(ex.ToString());
    }
  }

  public event MethodInvoker ButtonClicked;

  public void SayHello() {
    MessageBox.Show("Hello from Windows Forms");
  }

  public string ThemedBackgroundColor {
    get { return ColorTranslator.ToHtml(this.BackColor); }
    set { this.BackColor = ColorTranslator.FromHtml(value); }
  }
}

[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)]
public interface ISimpleEvents {
  [DispId(1)]//Each event must have a unique DispId
  void ButtonClicked();
}

 

NOTE: firing the ButtonClickedEvent requires UnmanagedCode permissions (essentially FullTrust) to execute.  This is because you are causing script code to execute which is not part of the managed CAS system and therefore considered unmanaged. 

In order to get this sample to work, you will need to "trust" the assembly hosting your managed control.

I did this for mine by adding my site to the "trusted sites zone" in internet explorer and with the command line:

caspol -m -ag 1.5 -url http://blogs.msdn.com/andrewdownum/* FullTrust

 

Published Thursday, January 26, 2006 12:00 PM by AndrewDownum
Filed under:

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# Common Issue: Security Exceptions

Thursday, February 16, 2006 11:21 AM by Andrew's Blog
If you are hosting a control in the browser and have given it elevated permissions (we will use FullTrust...

# re: Exposing Events from managed controls

Wednesday, March 01, 2006 9:32 AM by Steve
I've tried this a few times to implement this method but on each occasion it crashes with
"Microsoft JScript runtime error: 'simpleControl' is undefined"

# re: Exposing Events from managed controls

Saturday, March 11, 2006 5:19 PM by AndrewDownum
This is probably because you are attempting to access the control before it has been loaded in by the IE Document Object Model.

Make sure that you don't atempt to access the control before it is defined in the html page.

Leave a Comment

(required) 
required 
(required) 

  
Enter Code Here: Required
 
Page view tracker