Just about everyone has had to write logic in asp or asp.net to show a page/graphic giving a user something to look at while a webserver is processing some long running task (not unlike reading this sentence). Daniel Fisher shows how to build a control that does just that. The client side implementation of this control is sweet... drag it from the toolbox, set a property for the image location and hook up your event; that's it. He takes you step by step through the process, including implementing design time support. Check it out, very cool.
In Daniel's sample the delegate is hooked in the aspx declaration for the control. You may want to programatically hook it. The code for programatically hooking events got me thinking about the changes for delegates in 2.0... I modified the code for 2.0 - taking advantage of anonymous delegates and the shortened syntax for delegate assignment.
From the client you can hook the delegate like this in 2.0 this.WaitScreen1.Process += WaitScreen1_Process; where in 1.x you had to do: this.WaitScreen1.Process +=new EventHandler(WaitScreen1_Process);
In the control it gets easier also. In Daniel's code he simply fires the delegate (and for good reason, his sample was a demonstration of control building, not delegate best practice). The usual pattern for firing a delegate is to check for null beforehand. Also, there are race conditions to consider because in between checking the delegate for null and firing it, the delegate could become null. So if you want to optionally hook the delegate in the sample you'll need to add the null check to the code for the control. Or not! Enter anonymous delegates. In 2.0 you can get away with the following. Notice the use of an anonymous delegate (which does nothing) as a default assignment to the event.public event EventHandler Process = delegate { };public virtual void OnProcess() { Process(this, null);}So, Process will never be null; worst case scenario you've got an empty method executing. I did some quick Stopwatch performance analysis on this method vs. null checking and locking - the difference was almost nil. 25 ticks vs. 22 ticks on average (fractions of a millisecond).
I said earlier "you can get away with" the above code... best practice guidelines say your event declaration should be private with a public event handler. Also, it's a good idea for the method which does the firing to get the InvocationList and iterate through each in a try-catch block. You are executing untrusted code afterall, in the sense that the target method may throw an exception and the rest of the delegate instances will not execute. One of my .Net heroes, Juval Lowy, covers this in his outstanding book Programming .Net Components. private event EventHandler _process = delegate { };public event EventHandler Process { add { _process += value; } remove { _process -= value; }}
public virtual void OnProcess() { Delegate[] clients; clients = _process.GetInvocationList(); foreach (EventHandler client in clients) { try { client(this, EventArgs.Empty); } catch { _process -= client; } }}
Locking is recommended when publishing events in a remoting scenario, both when getting the Invocation List (and also in the event procedure when hooking and unhooking). Mike Woodring explains this here and has some other great tips on his site as well.