OdeToCode IC Logo

Silverlight Event Tokens

Thursday, September 27, 2007

Events are easy to add and remove when using the CLR and C#. Just sprinkle some += and -= in the right places and the runtime does the rest. Silverlight programming with JavaScript is a bit different, however, and although the addEventListener and removeEventListener appear similar to a DOM element's event registration APIs, these two methods have a twist.

As an example, let's say we wanted to listen to the MediaElement's BufferingProgressChanged event, but we want to stop listening once buffering has exceeded 50%. The following code does work:

function onLoad(rootElement)
{
    
var mediaElement = rootElement.findName("_media");
    mediaElement.addEventListener(
"BufferingProgressChanged",
                                  
"onBufferProgress");
}

function onBufferProgress(sender, eventArgs)
{      
    
// .. do something

    if(sender.BufferingProgress > 0.50)
    {
        sender.removeEventListener(
"BufferingProgressChanged",
                                    
"onBufferProgress");
    }
}

.. but this code will never unsubscribe from the event:

function onLoad(rootElement)
{
    
var mediaElement = rootElement.findName("_media");
    mediaElement.addEventListener(
"BufferingProgressChanged",
                                   onBufferProgress);
}

function onBufferProgress(sender, eventArgs)
{      
    
// .. do something

    if(sender.BufferingProgress > 0.50)
    {
        sender.removeEventListener(
"BufferingProgressChanged",
                                    onBufferProgress);
    }
}

When not using a quoted string to specify the event handler, you have to save the value returned from addEventListener. The return value is a token that is "just an integer value to track the order in which handlers were added for each object-event combination" (read MSDN for other subtleties in the event registration methods).

A proper unsubscribe looks like the following:

var token;

function onLoad(rootElement)
{
    
var mediaElement = rootElement.findName("_media");
    token = mediaElement.addEventListener(
                          
"BufferingProgressChanged",
                           onBufferProgress);
}

function onBufferProgress(sender, eventArgs)
{      
    
// .. do something

    if(sender.BufferingProgress > 0.50)
    {
        sender.removeEventListener(
"BufferingProgressChanged",
                                    token);
    }
}