When you think ASP, think...
Recent Articles
All Articles
ASP.NET Articles
ASPFAQs.com
Message Board
Related Web Technologies
User Tips!
Coding Tips
Search

Sections:
Book Reviews
Sample Chapters
Commonly Asked Message Board Questions
JavaScript Tutorials
MSDN Communities Hub
Official Docs
Security
Stump the SQL Guru!
Web Hosts
XML
Information:
Advertise
Feedback
Author an Article

ASP ASP.NET ASP FAQs Message Board Feedback
 
Print this Page!
Published: Wednesday, May 11, 2005

Bubbling Events Up the Control Hierarchy

By Scott Mitchell


Introduction


The DataGrid control, as you likely know, can easily be configured to add a column of buttons. By adding a ButtonColumn, whenever one of the DataGrid's buttons in the column is clicked, the Web page posts back and the DataGrid's ItemCommand event fires. In fact, the same behavior can be noted if you manually add a Button or LinkButton control into a DataGrid TemplateColumn, as the ButtonColumn class simply adds a Button (or LinkButton) Web control to each row of the DataGrid.

When the Button (or LinkButton) is clicked, its Command event is raised. But how does the DataGrid know when this event has been raised so that it can raise its ItemCommand event in response? The answer is through a process referred to as event bubbling. Event bubbling is the process of moving an event up the control hierarchy, from a control low in the hierarchy - such as a Button within the row of a DataGrid - and percolating it up to an ancestor control - such as the DataGrid. Once the ancestor control has learned of the event it can respond however it sees fit; in the DataGrid's case, the DataGrid "swallows" the Button's Command event (that is, it stops the bubbling) and raises its own ItemCommand event in response.

In this article we'll look at how, precisely, event bubbling works in ASP.NET. Event bubbling is a technique that all server control developers should be aware of. Additionally, it can be used as a means to pass event information from a User Control to its parent page, as discussed in Handle Events from Web User Controls (although personally I find it simpler to just use the technique of having the User Control raise its own events through the standard event firing syntax as discussed at An Extensive Examination of User Controls). Read on to learn more!

- continued -

Understanding the Control Hierarchy


All ASP.NET pages are represented in code as a hierarchy of controls. While ASP.NET page developers are accustomed to working in terms of the Visual Studio .NET designer and HTML and Web control syntax, this markup is automatically converted into a programmatically-created control hierarchy when an ASP.NET page is first visited (or first visited after a change to its .aspx page's content). To better understand this process, let me refer to a previous article of mine, Understanding ASP.NET View State:
All ASP.NET server controls can have a parent control, along with a variable number of child controls. The System.Web.UI.Page class is derived from the base control class (System.Web.UI.Control), and therefore also can have a set of child controls. The top-level controls declared in an ASP.NET Web page's HTML portion are the direct children of the autogenerated Page class. Web controls can also be nested inside one another. For example, most ASP.NET Web pages contain a single server-side Web Form, with multiple Web controls inside the Web Form. The Web Form is an HTML control (System.Web.UI.HtmlControls.HtmlForm). Those Web controls inside the Web Form are children of the Web Form.

Since server controls can have children, and each of their children may have children, and so on, a control and its descendents form a tree of controls. This tree of controls is called the control hierarchy. The root of the control hierarchy for an ASP.NET Web page is the Page-derived class that is autogenerated by the ASP.NET engine.

Whew! Those last few paragraphs may have been a bit confusing, as this is not the easiest subject to discuss or digest. To clear out any potential confusion, let's look at a quick example. Imagine you have an ASP.NET Web page with the following HTML portion:

<html>
<body>
  <h1>Welcome to my Homepage!</h1>
  <form runat="server">
    What is your name?
    <asp:TextBox runat="server" ID="txtName"></asp:TextBox>
    <br />What is your gender?
    <asp:DropDownList runat="server" ID="ddlGender">
      <asp:ListItem Select="True" Value="M">Male</asp:ListItem>
      <asp:ListItem Value="F">Female</asp:ListItem>
      <asp:ListItem Value="U">Undecided</asp:ListItem>
    </asp:DropDownList>
    <br />
    <asp:Button runat="server" Text="Submit!"></asp:Button>
  </form>
</body>
</html>

When this page is first visited, a class will be autogenerated that contains code to programmatically build up the control hierarchy. The control hierarchy for this example [is shown below:]

This concept of a control hierarchy works just the same with a DataGrid. Specifically, a DataGrid contains a child control for each of its rows. Each of these row controls contains a child for each of its columns. And each column control may contain further controls. For ButtonColumns, the column control would contain a single child control - either a Button or LinkButton control. For a TemplateColumn, the column control would contain its own hierarchy of children that composed the HTML markup and Web controls specified in the template.

For example, imagine we had a DataGrid with two columns, a ButtonColumn and a BoundColumn. When binding the DataGrid to a DataSource with three records, the DataGrid's control hierarchy might look like the following:

Bubbling Basics


When one of the DataGrid's Buttons are clicked, the Button's Command event is fired. When this happens we also want to have the DataGrid's ItemCommand event fire, but as the above figure illustrates, there is a bit of distance between the Button instance that was clicked and the DataGrid control. Event bubbling is employed to percolate the event from the Button control up to the DataGrid, where the ItemCommand event can be raised in response.

Event bubbling works using two protected methods of the Control class:

  • RaiseBubbleEvent(source, eventArgs) - when called, a specified event's information is bubbled up to control's parent. The source parameter is typically a reference to the object doing the bubbling (the actual Button control in the DataGrid example), whereas the eventArgs contains information about the event being bubbled (in the DataGrid example, the Button's CommandEventArgs information is percolated up, which includes the Button's CommandName and CommandArgument parameters).
  • OnBubbleEvent(source, eventArgs) - when an event is bubbled up to a control, the control's OnBubbleEvent() method fires. A control in the hierarchy may override this method to do some custom processing on the bubbled event. In the DataGrid's case, the OnBubbleEvent() method checks to see if a CommandEventArgs instance is being bubbled up. If so, it raises its own ItemCommand event. (This is a slight simplification of how things really work with the DataGrid.)

    The OnBubbleEvent() method returns a Boolean value that indicates if bubbling of the event should continue. If OnBubbleEvent() returns False, the event continues to bubble up the hierarchy; if it returns True, the bubbling of that event ends. By default, a control's OnBubbleEvent() returns False, thereby allowing event bubbling to progress unimpeded.

To demonstrate event bubbling, image that the Button in the third DataGrid row is clicked. Clicking the Button causes a postback and raises the appropriate Button control's Click event handler. The Button (and LinkButton) Web control's are coded such that when their Command event is fired, the event details are bubbled up the hierarchy. Specifically, the OnCommand() method in the Button and LinkButton classes looks as follows (comments added by yours truly):

Protected Overridable Sub OnCommand(ByVal e As CommandEventArgs)
  'OnCommand is passed in the CommandEventArgs for the event...
  Dim handler1 As CommandEventHandler = _
       CType(MyBase.Events.Item(Button.EventCommand), CommandEventHandler)

  If (Not handler1 Is Nothing) Then
    'This raises the event...
    handler1.Invoke(Me, e)
  End If

  'The call to RaiseBubbleEvent starts the percolation of the
  'event up the control hieracrhy.
  MyBase.RaiseBubbleEvent(Me, e)
End Sub

This event is then bubbled up to the ButtonColumn, calling its OnBubbleEvent() method, which, by default, does nothing, thereby letting the bubbling continue. Following that, the DataGridItem's OnBubbleEvent() method is called. The DataGridItem's OnBubbleEvent() checks to see if a CommandEventArgs object is being bubbled up and, if so, it crafts an instance of the DataGridCommandEventArgs object based on the passed-in CommandEventArgs object. This new type is then bubbled up to its parent (the DataGrid) and event bubbling is ceased. Here's the code from the DataGridItem's OnBubbleEvent() method:

Protected Overrides Function OnBubbleEvent(ByVal source As Object, _
                                           ByVal e As EventArgs) As Boolean
  If TypeOf e Is CommandEventArgs Then
     'Craft a DataGridCommandEventArgs object from the CommandEventArgs...
     Dim args1 As New DataGridCommandEventArgs(Me, _
                           source, CType(e, CommandEventArgs))
                           
     'Bubble the new DataGridCommandEventArgs
     MyBase.RaiseBubbleEvent(Me, args1)
     
     'Stop the bubbling of the CommandEventArgs
     Return True
  End If
  
  'If we are dealing with something other than a CommandEventArgs,
  'let the bubbling proceed unmolested...
  Return False
End Function

Finally, in the DataGrid's OnBubbleEvent() method a check is made to see if a DataGridCommandEventArgs object has been bubbled up. If so, it halts the bubbling and raises its ItemCommand event. (Note that the DataGrid's OnBubbleEvent() method is a bit more complex than the DataGridItem's because the DataGrid might raise a number of events based on the CommandName value in the DataGridCommandEventArgs object. (For example, a CommandName of Edit raises the EditCommand event, a CommandName of Update raises the UpdateCommand event, and so on. Of course, regardless of the CommandName the ItemCommand always fires.)

The following figure depicts the chain of events just described:

Conclusion


In this article we saw how event bubbling is used to percolate events up the control hierarchy. This technique is an invaluable one for control developers creating composite controls whose contents cannot be determined until runtime. The most common Web control that fits into this class is the DataGrid, although both the DataList and Repeater use event bubbling in a similar manner. For more information on creating these types of controls, along with a further discussion on event bubbling, be sure to read Building DataBound Templated Custom ASP.NET Server Controls.

Happy Programming!

  • By Scott Mitchell



  • ASP.NET [1.x] [2.0] | ASPMessageboard.com | ASPFAQs.com | Advertise | Feedback | Author an Article