Skip navigation

Extend the GridView Control

Handling Data Binding Events in GridView

The server-side data binding techniques introduced inASP.NET 1.x revolutionized the way developers build pages that access data. With the introduction of data-bound controls in ASP.NET 2.0, you now have a whole range of features at your disposal that can be used for filtering, sorting and paging, editing, and deleting data. GridView is one of the important data-bound controls that automatically handles these operations as long as the bound data source control supports these capabilities. In addition to GridView s out-of-the-box features, you also have the option of extending these built-in capabilities by intercepting the various events of the GridView control. Specifically, by handling the data binding events, you can support rich data-bound scenarios when the out-of-the-box capabilities fall short of your requirements. This article takes a detailed look at the data binding events supported by the GridView control and discusses the steps involved in implementing these events. To this end, you ll see advanced examples on using these events to create sophisticated ASP.NET Web applications.

 

Introduction to Data Binding

The main reason for using data binding is to save you code through a declarative approach. For example, you can use the simple data binding features of GridView to retrieve and display data with no code at all. Although this approach works for many simple scenarios, there are times when you might want to extend this data binding when the simple data binding output doesn t meet your needs. Consider the scenario wherein you want to display embedded GridViews that display master-detail data in an ASP.NET page. To accomplish this, you need to intercept one of the GridView data binding events and write code to retrieve the right data to display the parent and child GridView controls. When displaying data in the GridView, the main binding events fire in the order shown in Figure 1.

 

Event Name

Description

DataBinding

Raised when the GridView control binds to a data source.

RowCreated

Enables you to affect the row before the GridView has been bound to the fields.

RowDataBound

Enables you to affect the row after the GridView has been bound, and evaluate the GridView that has been bound.

DataBound

Raised after the GridView control binds to a data source.

Figure 1: When displaying data in the GridView, the main binding events fire in this order.

 

Note that the RowCreated and RowDataBound events fire for each row bound to the GridView control. The rich event model allows you to intercept the render of your view control at any point in the binding process. For selecting objects, the RowDataBound event is useful, because you can gain access to both the bound row and your object, which is useful for applying formatting to your row. For adding custom content to the data rows, such as injecting client-side script, use the RowCreated event.

To demonstrate the data binding events supported by the GridView control, consider the following scenarios wherein you expose rich data binding capabilities:

  • Using embedded GridView controls for displaying parent-child data
  • Injecting client-side script
  • Displaying a summary row using the GridView control

 

Using Embedded GridView Controls

In this section, you ll see an example for creating a parent/child report that shows all the records from the child table, organized by parent. For the purposes of this example, consider displaying a complete list of products organized by category in the AdventureWorks database. The basic technique is to create a GridView for the parent table that contains an embedded GridView for each row. These child GridView controls are inserted into the parent GridView using a TemplateField. The only trick is that you cannot bind the child GridView controls at the same time that you bind the parent GridView, because the parent rows have not been created yet. Instead, you must wait for the GridView.RowDataBound event to fire in the parent. The code required to achieve this output is shown in Listing One.

In this example, the parent GridView defines two columns, both of which are the TemplateField type. The first column combines the category id and category name (see Figure 2); the second contains an embedded GridView of products, with two bound columns (see Figure 3).



 

 

   
<%# Eval("ProductSubcategoryID") %>

<%# Eval("Name") %>

Figure 2: The parent GridView defines two columns; this one combines the category id and category name.



 

 

  

    

      

      

      

    

  

 

 

Figure 3: The parent GridView defines two columns; this one contains an embedded GridView of products.

Now all you need to do is create two data sources, one for retrieving the list of categories and the other for retrieving all products in a specified category. The first query fills the parent GridView; the second query is called multiple times to fill the child GridView. You can bind the first grid directly to the data source, as shown here:

 

This part of the code is typical. The trick is to bind the child GridView controls. If you omit this step, the child GridView controls will not appear.

To bind the child GridView controls, you must react to the GridView.RowDataBound event, which fires every time a row is generated and bound to the parent GridView. At this point, you can retrieve the child GridView control from the second column and bind it to the product information by programmatically calling the Select method of the data source. To ensure that you show only the products in the current category, you must also retrieve the CategoryID field for the current item and pass it as a parameter. The code you need is shown in Figure 4; Figure 5 shows the resultant output generated.

void gridCategories_RowDataBound(object sender,

 GridViewRowEventArgs e)

{

 if (e.Row.RowType == DataControlRowType.DataRow)

 {

 //Retrieve the GridView control in the second column

 GridView gridProducts = (GridView)e.Row.Cells[1].Controls[1];

 //Set the CategoryID parameter to return the products

 //for the current category

 string categoryID=

   gridCategories.DataKeys[e.Row.DataItemIndex].Value.ToString();

 productSource.SelectParameters[0].DefaultValue = categoryID ;

 gridProducts.DataSource =

   productSource.Select(DataSourceSelectArguments.Empty);

 gridProducts.DataBind();

 }

}

Figure 4: Retrieve the CategoryID field for the current item and pass it as a parameter ...


Figure 5: ... to show only the products in the current category.

 

Injecting Client-side Script

By default, GridView provides built-in support for single row selection. It is also possible for you to extend the single row selection to multiple rows using a few lines of code. However, when you select multiple rows, it would be nice if you could change the background color of the selected row so that you can easily identify all the selected rows. To implement this, you need to be able to inject client-side script for each of the rows displayed through the GridView. The right place to do this is the GridView.RowCreated event. The complete code required to implement this solution is shown in Listing Two.

The key in the code shown in Listing Two is the RowCreated event handler, where you inject a block of code that does the job of highlighting the rows in the GridView whenever a row is selected. To inject this block of code, use the RegisterStartupScript method of the ClientScriptManager object:

Page.ClientScript.RegisterStartupScript(this.GetType(),

 "RowCreatedScript", script, true); 

After inserting the code, you associate that with the JavaScript onclick event of the checkbox:

chkBox.Attributes.Add("onclick", "HighlightSelected(this,'" +

 Convert.ToString(e.Row.RowState) + "' );") ; 

If you navigate to the page in the browser, you should see an output that is somewhat similar to the screenshot shown in Figure 6.


Figure 6: Injecting client-side script through the RowCreated event handler.

If you select a couple of rows in the GridView, you ll see the background color of the selected rows change to a different color, similar to that shown in Figure 7.


Figure 7: Selected rows in the GridView change color.

 

Displaying Summary Row Using the GridView Control

Although the prime purpose of a GridView is to show a set of records, you can also add more interesting information, such as summary data, by intercepting the RowDataBound event. The first step is to add the footer row by setting the GridView.ShowFooter property to true. This displays a shaded footer row (which you can customize freely), but it doesn t show any data. To take care of that task, insert the content into the GridView.FooterRow.

For example, imagine you are dealing with a list of special offers. A simple summary row could display the summary for each type of special offer. The first step is to decide when to calculate this information. If you are using manual binding, you could retrieve the data object and use it to perform your calculations before binding it to the GridView. However, if you are using declarative binding, you need another technique. You have two basic options you can retrieve the data from the data object during the binding operation, or you can retrieve it from the grid itself after the grid has been bound. The following example uses the former approach because it gives you the freedom to use the same calculation code no matter what data source was used to populate the control. It also gives you the ability to total only the records that are displayed on the current page, if you have enabled paging. The disadvantage is that your code is tightly bound to the GridView, because you need to pull out the information you want by position, using hard-coded column index numbers.

As in the previous examples, the basic strategy is to react to the GridView.RowDataBound event. This occurs immediately after each row in the GridView is populated with data. At this point, you calculate the summary by retrieving the type of discount type from the current row. Once this total is calculated, it is inserted into the footer row. Listing Three shows the complete code.

In the RowDataBound event, you check to see if the current row is a footer row using the DataRowControlType enumeration. Figure 8 shows the output generated by the page.


Figure 8: Output generated by using the DataRowControlType enumeration.

 

Conclusion

This article provides a detailed discussion of the events supported by the GridView control. You have also been introduced to the advanced data binding capabilities of GridView, through which you can create sophisticated Web sites. As you can see, the data binding events are very extensible in that they provide you with hooks into the data binding lifecycle, making it extremely easy to build sophisticated ASP.NET applications.

The code accompanying this article is available for download.

Thiru Thangarathinam is an MVP who specializes in architecting, designing, and developing distributed enterprise-class applications using .NET-related technologies. He is the author of Professional ASP.NET 2.0 XML from Wrox and has co-authored a number of books in .NET-related technologies. He has also been a frequent contributor to leading technology-related online publications. He can be reached at mailto:[email protected].

 

Begin Listing One

<%@ Page Language="C#" %>







 Using RowDataBound event to create

    embedded GridViews






<%# Eval("ProductSubcategoryID") %>

<%# Eval("Name") %>

End Listing One

 

Begin Listing Two

<%@ Page Language="C#" %>







 Injecting Client Side Script through RowCreated Event






<%# Eval("Name") %>


<%# Eval("ProductNumber") %>


<%# Eval("ListPrice") %>

End Listing Two

 

Begin Listing Three

<%@ Page Language="C#" %>





 Displaying Summary Data in a Footer

    using GridView

 





End Listing Three

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish