Handle users leaving your page in Silverlight (OnBeforeUnload and a weak event handler)

I know it’s not ideal to prompt a user ‘You’re leaving, do you want to save changes?’ but sometimes you’ve got to.  Recently we had a requirement which stated the user must be warned when leaving our application if they are on an active phone call.  It’s not difficult to do as you can subscribe to the JavaScript ‘onbeforeunload’ event.  Expose a scriptable object out of Silverlight and hook it up.  Job done.

However, you’ve got to make sure you don’t introduce a memory leak.  Now, ordinarily you could use a composite presentation event, which as I mentioned before, can use weak references.  But you can’t do that so easily here because you need to respond to the event setting some value so that the browser can show a warning.  And because the composite events are dispatched it would be tricky and a bit of a hack to use them.  So, I need to implement my own weak event.

Again, this is pretty easy if you have a Weak Collection.  The MVVM framework we’re using (Photon) has one built in.  I’ll be blogging more about Photon and MVVM soon I hope, time allowing (I had a blow out on the motorway and it appears no tyre places are open Sundays, so train for me!).  In the mean time there is some documentation on codeplex so go check it out.

As a pattern I’m going to copy the one used here in the CommandManager (it has a static event, RequerySuggested).  It’s a bit smelly because the person subscribing to the event has to make sure they hold a reference to the delegate.  You can’t say c.RequerySuggested += DoSomething; because nothing will hold a strong reference.  This is described in the remarks in the MSDN documentation.  I think it’s good to be consistent with APIs as at least people get what they expect…

public class SilverlightApplication
{
    private static SilverlightApplication current;
 
    private readonly WeakCollection<EventHandler<BeforeExitEventArgs>> beforeExitEvents = new WeakCollection<EventHandler<BeforeExitEventArgs>>();
 
    public event EventHandler<BeforeExitEventArgs> BeforeExit
    {
        add
        {
            beforeExitEvents.Add(value);
        }
        remove
        {
            beforeExitEvents.Remove(value);
        }
    }
 
    public static SilverlightApplication Current
    {
        get
        {
            return current ?? (current = new SilverlightApplication());
        }
        set
        {
            current = value;
        }
    }
 
    [ScriptableMember]
    public virtual string OnBeforeExit()
    {
        var args = new BeforeExitEventArgs();
        foreach (var handler in beforeExitEvents)
        {
            handler(this, args);
 
            if (!string.IsNullOrEmpty(args.Warning))
            {
                return args.Warning;
            }
        }
 
        return null;
    }   
}

And to use it:

private EventHandler<BeforeExitEventArgs> exitEvent;
 
private void SubscribeToExit()
{
    exitEvent = new EventHandler<BeforeExitEventArgs>((s, e) => e.Warning = "sure?");
    SilverlightApplication.Current.BeforeExit += exitEvent;
}

Last bit is to hook it up in Javascript.

function CheckClose() {
    var result = document.getElementById("app").content.silverlightApplication.OnBeforeExit();
    if (result != null) return result;
}
Advertisements

About Tom Peplow

C# .Net developer based in London and the South Coast
This entry was posted in Uncategorized and tagged , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s