RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Web Control Templates Explained : Page 4

Programming for extensibility assures ease of maintainability in your design. Control templates offer this functionality to custom Web controls.

Event Bubbling
When I created the EmailContact control I added several child controls into it, one of which required some amount of event handling. The button I added into my control to perform the actual e-mail sending raised its Click event as any button will. What's important to realize here is that a control raises an event only to its parent, so in this case the "send" button raised its Click event to its parent, the EmailContact control. In the method I wrote that captured the button's event, I made the decision to either handle the event or fire a new event up to my control's parent, the form. This is standard operating procedure for child control event handling within composite Web controls. However, when I injected template functionality into the control, I did so completely aware that the page developer might put some links or buttons into one of my templates. In fact, I don't know what the page developer may throw into my templates and I need to account for actions that may need to be taken on such template content.

Event bubbling allows the bubbling up of unhandled events and their management from one centralized location.
This is where event bubbling comes into play. The concept of event bubbling means taking unhandled events and shooting them up the chain of parent controls until they reach the surface; the form. So now you're probably under the impression that any event raised by any control inserted into a template will be handled by event bubbling—wrong. Event bubbling does not happen magically, it must be ordered by the controls when they fire their events. In the case of Microsoft's ASP.NET controls, not all events order bubbling to take place. In fact, only three controls contain this functionality: Button, LinkButton, and ImageButton. Not only that, but in these controls it's not the Click event that orders bubbling to take place, it's another event called Command.

If you've ever wondered why buttons and links have this event, bubbling is the reason. A button's (or link) Click event does not automatically bubble up, but its Command event does. Let me give you a peek into the code for the ASP.NET Button control. The button's Click event is raised within a method called OnClick and its code looks something like this:

   Protected Overridable Sub OnClick( _
      ByVal e As EventArgs)
      RaiseEvent Click(Me, e)
   End Sub
The Command event is raised within a method called OnCommand which contains the following code:

   Protected Overridable Sub OnCommand( _
      ByVal e As CommandEventArgs)
      RaiseEvent Command(Me, e)
      RaiseBubbleEvent(Me, e)
   End Sub
Both events are raised by the Button control back to back, with their only difference being what you see in the code above. The Command event also makes a call to the RaiseBubbleEvent method and it is this method call that orders event bubbling to take place. This bubbling order will now continue up the chain until it is finally handled somewhere along the way. You handle events that are bubbled up a chain by overriding the OnBubbleEvent method.

So let's reiterate where I've taken you so far. I've explained that buttons and links are already set up to bubble up their Command event. This gives me something to rely on in the EmailContact control. Should a page developer drop a link or a button into one of my templates, I can now override the OnBubbleEvent method in the EmailContact control in order to handle the bubbling coming from any controls dropped into one of my templates. Let's see what that looks like.

   Protected Overrides Function OnBubbleEvent( _
      ByVal source As Object, ByVal e As EventArgs) _
      As Boolean
      If source.ID <> "btnSend" AndAlso _
         TypeOf e Is CommandEventArgs Then
         Dim cmd As CommandEventArgs = _
            CType(e, CommandEventArgs)
         RaiseEvent ItemCommand(Me, _
            New CommandEventArgs(cmd.CommandName, _
         Return True 'cancel further bubbling
         Return False
      End If
   End Function
This code is actually quite simple. The first thing I'm doing here is checking to make sure it was not the control's "send" button that got me here. I'm also doing a check to make sure the event argument object sent in is of type CommandEventArgs. This is the event argument object that the CommandEventHandler delegate uses which defines the Command event of all buttons and links. More often than not, you're probably going to be doing this check unless you start issuing RaiseBubbleEvent orders from your own events.

I'm casting the EventArgs object that came in to the type CommandEventArgs so I have strong-typing, then I'm raising an ItemCommand event that I declared in the EmailContact control.

   Public Event ItemCommand As EventHandler(
      Of CommandEventArgs)
Raising the ItemCommand event is the protocol defined by Microsoft for sending bubbled events up to the form. It's important that control developers follow this protocol in order to provide consistency with the Microsoft controls—besides, it works!

The standard protocol for the ItemCommand event is to receive a CommandEventArgs object which contains a CommandName and CommandArgument property. These two properties come from the buttons and links and identify the button or link that the user clicked, giving a cleaner approach than using the sender argument of an event.

Finally, the method cancels any further event bubbling from taking place. By returning a True value, I'm telling the EmailContact control that the buck stops here. My control has now assumed all responsibility for the bubbled events and has taken appropriate action by raising its ItemCommand event.

What I've just explained is exactly what the ASP.NET grid controls do and why you must trap the ItemCommand event from the grid in order to receive clicks from buttons or links that template columns may contain. So now I can receive the EmailContact control's ItemCommand event and identify a click from a contained link or button.

   Protected Sub EmailContact1_ItemCommand( _
      ByVal sender As Object, _
      ByVal e As CommandEventArgs) _
      Handles EmailContact1.ItemCommand
      ' use e.CommandName and/or e.CommandArgument
      ' to determine what link or button was clicked
   End Sub
Incidentally, the CommandName and CommandArgument properties of buttons and links are freeform text properties that you can use for anything that you want to identify the control. In the case of a repeatable control such as a grid, you could drag a couple of links into a template column and they will be repeated on every row. You can use the CommandName property to identify a clicked link; then you can use the grid's DataKeyField property to determine which row contained the clicked control.

So I hope I've taken some mystery out of how controls contained in grid templates send their events up to the form. The last thing I need to add to my control is some design-time functionality. In ASP.NET 1.1 (and 1.0), you right-clicked on a control with template functionality, such as the grid, and you'd see context menu commands that allow you to edit templates using the designer. Once in "template-editing" mode, you could drag controls into a template column from the toolbox. Unfortunately, you couldn't easily build this design-time functionality into your own custom controls. With ASP.NET 2.0 that changes. You can add designer functionality for controls with templates, without which you would have to work in ASPX mode as the code examples I showed you earlier demonstrated.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date