This blog has moved to http://ikhwanhayat.net

Monday, November 28, 2005

AddHandler in Data Bound Controls

I have a parent-child kind of data, and to list it I need a DataList with a DataGrid in it's row. Get it? Okay, this looks like a good place to show-off my ASCII arting prowess.

+=DataList==================================+
|   Item1  [remove]                         |
|    +-DataGrid-------------------------+   |
|    |   Item1.1              [delete]  |   |
|    |   Item1.2              [delete]  |   |
|    |   Item1.3              [delete]  |   |
|    |   Item1.4              [delete]  |   |
|    +----------------------------------+   |
+===========================================+
|   Item2  [remove]                         |
|    +-DataGrid-------------------------+   |
|    |   Item2.1              [delete]  |   |
|    |   Item2.2              [delete]  |   |
|    |   Item2.3              [delete]  |   |
|    +----------------------------------+   |
+===========================================+
Actually making the data come out like this is not really that hard. Just make an event handler for the ItemDataBound of the DataList, and add codes to DataBind the child rows to the DataGrid. Like so:
Protected dlParent As DataList
Protected ParentTable As DataTable
Protected ChildTable As DataTable
.
.
Private Sub dlParent_ItemDataBound(ByVal sender As Object, _
    ByVal e As System.Web.UI.WebControls.DataListItemEventArgs) _
    Handles dlParent.ItemDataBound
    If (e.Item.ItemType = ListItemType.Item _
        OrElse e.Item.ItemType = ListItemType.AlternatingItem) Then
        
        Dim dgChild As DataGrid 
        dgChild = DirectCast(e.Item.FindControl("dgChild"), DataGrid)
        Dim parentID As String
        parentID = DirectCast(e.Item.DataItem, DataRowView)("ParentID").ToString()
        
        Dim dv As DataView = ChildTable.DefaultView
        dv.RowFilter = "ParentID=" & parentID
        dgChild.DataSource = dv
        dgChild.DataBind()
        
    End If
End Sub
The confusing part is how to handle the event for the [delete] button in the DataGrid. The intention is to delete the particular child item from the ChildTable. The first thing comes into my mind is to dinamically attach an event handler ItemCommand to the DataGrid. So I just make an AddHandler in the dlParent_ItemDataBound, and write the appropriate event handler :
.
        ' in the dlParent_ItemDataBound
        AddHandler dgChild.ItemCommand, AddressOf Child_ItemCommand
.
.
' The event handler
Private Sub Child_ItemCommand(ByVal source As Object, _
    ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs)
    
    ' Deletion routines here
    
End Sub
This is where I did wrong. I tried this one over and over. Everything seems fine, but the event handler is just not being invoked at all. After some Googling (like always), I came to a solution. What I should do is make the AddHandler in the ItemCreated event, not in the ItemDataBound event. It worked like a charm. Another job (almost) well done. Thanks to this page, http://www.codecomments.com/archive289-2004-8-268077.html
ItemDataBound isn't invoked on postback because the control isn't databound back to the source, the viewstate is used. If you put a breakpoint/trace in ItemDataBound you'll see it isn't called. handlers added dynamically don't preserve their state on postback, so you need to add them somewhere around the page_load event (not exactly sure what's the latest you can get away with). You can either put the code in the ItemCreated or in Page_Load if Page.IsPostBack is true.

0 Comments:

Post a Comment

<< Home