Working with GridView Control Events The GridView control includes a rich set of events that you can handle to customize the control's behavior and appearance. These events can be divided into three groups. First, the GridView control supports the following set of events that are raised when the control displays its rows: DataBinding Raised immediately before the GridView is bound to its data source. DataBound Raised immediately after a GridView is bound to its data source. RowCreated Raised when each row in the GridView is created. RowDataBound Raised when each row in the GridView is bound to data. Second, the GridView control includes the following set of events that are raised when you are editing records: RowCommand Raised when an event is raised by a control contained in the GridView. RowUpdating Raised immediately before a GridView updates a record. RowUpdated Raised immediately after a GridView updates a record. RowDeleting Raised immediately before a GridView deletes a record. RowDeleted Raised immediately after a GridView deletes a record. RowCancelingEdit Raised when you cancel updating a record. Finally, the GridView control supports the following events related to sorting, selecting, and paging: PageIndexChanging Raised immediately before the current page is changed. PageIndexChanged Raised immediately after the current page is changed. Sorting Raised immediately before sorting. Sorted Raised immediately after sorting. SelectedIndexChanging Raised immediately before a row is selected. SelectedIndexChanged Raised immediately after a row is selected. In this section, you learn how to handle the RowDataBound event (my favorite event included with the GridView control) to create GridView special effects. You learn how to handle the RowDataBound event to highlight particular rows, show column summaries, and create nested Master/Detail forms. Highlighting GridView Rows Imagine that you want to highlight particular rows in a GridView. For example, when displaying a table of sales totals, you might want to highlight the rows in which the sales are greater than a certain amount. You can modify the appearance of individual rows in a GridView control by handling the RowDataBound event. For example, the page in Listing 11.28 displays every movie that has a box office total greater than $300,000.00 with a yellow background color (see Figure 11.20). Figure 11.20. Highlighting rows in the GridView control. Listing 11.28. HighlightRows.aspx [View full width] <%@ Page Language="VB" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <script runat="server"> Protected Sub grdMovies_RowDataBound(ByVal sender As Object, ByVal e As GridViewRowEventArgs) If e.Row.RowType = DataControlRowType.DataRow Then Dim boxOfficeTotals As Decimal = CType(DataBinder.Eval(e.Row.DataItem, "BoxOfficeTotals"), Decimal) If boxOfficeTotals > 300000000 Then e.Row.BackColor = System.Drawing.Color.Yellow End If End If End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Highlight Rows</title> </head> <body> <form runat="server"> <div> <asp:GridView DataSource OnRowDataBound="grdMovies_RowDataBound" AutoGenerateColumns="false" Runat="server"> <Columns> <asp:BoundField DataField="Title" HeaderText="Title" /> <asp:BoundField DataField="BoxOfficeTotals" DataFormatString="{0:c}" HtmlEncode="false" HeaderText="Box Office Totals" /> </Columns> </asp:GridView> <asp:SqlDataSource ConnectionString="<%$ ConnectionStrings:Movies %>" SelectCommand="SELECT * FROM Movies" Runat="server" /> </div> </form> </body> </html> | In Listing 11.28, the grdMovies_RowDataBound() method is executed when the GridView renders each of its rows (including its header and footer). The second parameter passed to this event handler is an instance of the GridViewRowEventArgs class. This class exposes a GridViewRow object that represents the row being bound. The GridViewRow object supports several useful properties (this is not a complete list): Cells Represents the collection of table row cells associated with the row being bound. DataItem Represents the data item associated with the row being bound. DataItemIndex Represents the index of the data item in its DataSet associated with the row being bound. RowIndex Represents the index of the row being bound. RowState Represents the state of the row being bound. Possible values are Alternate, Normal, Selected, Edit. Because these values can be combined (for example, the RowState can be Alternate Edit), use a bitwise comparison with RowState. RowType Represents the type of row being bound. Possible values are DataRow, Footer, Header, NullRow, Pager, Separator. In Listing 11.28, the RowType property is used to verify that the row is a DataRow (not a header row or some other type of row). The DataItem property is used to retrieve the database record associated with the row. Notice that the DataBinder.Eval() method is used to retrieve the value of the BoxOfficeColumn. Displaying Column Summaries Imagine that you want to display a column total at the bottom of a column. In that case, you can handle the GridView RowDataBound event to sum the values in a column and display the summary in the column footer. For example, the page in Listing 11.29 contains a GridView control that displays a summary column representing the total box office sales of all movies (see Figure 11.21). Figure 11.21. Displaying a column summary. Listing 11.29. SummaryColumn.aspx [View full width] <%@ Page Language="VB" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <script runat="server"> Private _boxOfficeTotalsTotal As Decimal = 0 Protected Sub grdMovies_RowDataBound(ByVal sender As Object, ByVal e As GridViewRowEventArgs) If e.Row.RowType = DataControlRowType.DataRow Then Dim boxOfficeTotals As Decimal = CType(DataBinder.Eval(e.Row.DataItem, "BoxOfficeTotals"), Decimal) _boxOfficeTotalsTotal += boxOfficeTotals End If If e.Row.RowType = DataControlRowType.Footer Then Dim lblSummary As Label = CType(e.Row.FindControl("lblSummary"), Label) lblSummary.Text = String.Format("Total: {0:c}", _boxOfficeTotalsTotal) End If End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Summary Column</title> </head> <body> <form runat="server"> <div> <asp:GridView DataSource OnRowDataBound="grdMovies_RowDataBound" AutoGenerateColumns="false" ShowFooter="true" Runat="server"> <Columns> <asp:BoundField DataField="Title" HeaderText="Title" /> <asp:TemplateField HeaderText="Box Office Totals"> <ItemTemplate> <%# Eval("BoxOfficeTotals", "{0:c}") %> </ItemTemplate> <FooterTemplate> <asp:Label Runat="server" /> </FooterTemplate> </asp:TemplateField> </Columns> </asp:GridView> <asp:SqlDataSource ConnectionString="<%$ ConnectionStrings:Movies %>" SelectCommand="SELECT * FROM Movies" Runat="server" /> </div> </form> </body> </html> | Notice that the GridView control uses a TemplateField to represent the BoxOfficeTotals column. The TemplateField includes a <FooterTemplate> that contains a Label control. The grdMovies_RowDataBound() method displays the total of the box office totals in this Label control. Displaying Nested Master/Details Forms You also can handle the RowDataBound event to create nested Master/Details forms. The page in Listing 11.30 displays a list of movie categories and displays a list of matching movies under each category (see Figure 11.22). Figure 11.22. Displaying a nested Master/Detail form. Listing 11.30. NestedMasterDetail.aspx [View full width] <%@ Page Language="VB" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <script runat="server"> Protected Sub grdMovieCategories_RowDataBound(ByVal sender As Object, ByVal e As GridViewRowEventArgs) If e.Row.RowType = DataControlRowType.DataRow Then Dim categoryId As Integer = CType(DataBinder.Eval(e.Row.DataItem,"Id"), Integer) Dim srcMovies As SqlDataSource = CType(e.Row.FindControl("srcMovies"), SqlDataSource) srcMovies.SelectParameters("CategoryId").DefaultValue = categoryId.ToString() End If End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <style type="text/css"> .categories h1 { font:bold 16px Arial, Sans-Serif; } .movies { margin-left:20px; margin-bottom:10px; width:100%; } </style> <title>Nested Master/Detail</title> </head> <body> <form runat="server"> <div> <asp:GridView DataSource OnRowDataBound="grdMovieCategories_RowDataBound" AutoGenerateColumns="false" Css ShowHeader="false" GridLines="none" Runat="server"> <Columns> <asp:TemplateField> <ItemTemplate> <h1><%# Eval("Name") %></h1> <asp:GridView DataSource Css GridLines="none" Runat="server" /> <asp:SqlDataSource ConnectionString="<%$ ConnectionStrings:Movies %>" SelectCommand="SELECT Title,Director FROM Movies WHERE CategoryId=@CategoryId" Runat="server"> <SelectParameters> <asp:Parameter Name="CategoryId" /> </SelectParameters> </asp:SqlDataSource> </ItemTemplate> </asp:TemplateField> </Columns> </asp:GridView> <asp:SqlDataSource ConnectionString="<%$ ConnectionStrings:Movies %>" SelectCommand="SELECT Id,Name FROM MovieCategories" Runat="server" /> </div> </form> </body> </html> | The grdMovieCategories_RowDataBound() method handles the RowDataBound event. This event handler grabs the movie category ID from the current row's DataItem property. Next, it retrieves the SqlDataSource control contained in the grdMovieCategories TemplateField. Finally, it assigns the movie category ID to a parameter contained in the SqlDataSource control's SelectParameters collection. Note Notice that you must use the FindControl() method to get the SqlDataSource control from the TemplateField. The templates in a TemplateField each create their own naming containers to prevent naming collisions. The FindControl() method enables you to search a naming container for a control with a matching ID. |