Checkboxes on a Datagrid with paging and sorting

By:  Robert Beaubien, Sr. Programmer, Kool Software, MCP
Published: July 28th, 2003
Tested with: VisualStudio.NET 2003, .NET Framework 1.1
VB Source Download:  dg_checkbox.zip

I had a need to allow users to select records for processing in a datagrid that employed paging and sorting.  I've come up with a neat solution to the problem.

Here is a link to a working version:  http://test.koolsoft.com/dg_checkbox.aspx

My datagrid has some advanced features like reverse sorting and, of course, the runtime created checkboxes.  This sample uses the Northwind Orders table and we are only talking about he checkboxes in this article.

First, I create an empty template column in the datagrid to hold the checkbox.  Next, a checkbox has to be created for each row displayed in the datagrid.  This is done on the grid "ItemCreated" event...

Private Sub DataGrid1_ItemCreated(ByVal sender As Object, _
ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs) Handles DataGrid1.ItemCreated

  If (e.Item.ItemType = ListItemType.Item) Or (e.Item.ItemType = ListItemType.AlternatingItem) Then 
    AddCheckbox(e) 
  End If
End Sub

Private Sub AddCheckbox(ByVal e As DataGridItemEventArgs) 

  Dim cb As New CheckBox
  Dim cell As TableCell = e.Item.Cells(0)
  cb.EnableViewState = True
  cb.AutoPostBack = True
  cb.ID = e.Item.ItemIndex
  cell.HorizontalAlign = HorizontalAlign.Right
  AddHandler cb.CheckedChanged, AddressOf OnCheckedChangedEvent
  cell.Controls.Add(cb)

End Sub

In the ItemCreated event, only add the checkbox on the actual Items (or AlternatingItem) and not the header or footer.  The AddCheckbox sub defines a new checkbox, gets the first column, sets some properties on the checkbox, adds the event handler to the checkbox and adds the checkbox to the cell.

Next, when the grid is binding data, I determine if the row has already been checked or not and set the checkbox appropriately.

Private Sub DataGrid1_ItemDataBound(ByVal sender As Object, _
ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs) Handles DataGrid1.ItemDataBound

  Dim chkvalue As String
  Dim chkText As String
  Dim cb As CheckBox
  Dim litem As ListItem
  If (e.Item.ItemType = ListItemType.Item) Or (e.Item.ItemType = ListItemType.AlternatingItem) Then
    chkText = e.Item.Cells(2).Text.ToString
    chkvalue = e.Item.Cells(1).Text.ToString
    cb = CType(e.Item.Cells(0).Controls(0), CheckBox)
    litem = New ListItem(chkText, chkvalue)
    If ListBox1.Items.Contains(litem) Then
      cb.Checked = True
    Else
      cb.Checked = False
    End If
    litem = Nothing
  End If

End Sub

Again, I only affect changes when this is an item or alternatingitem.   I get the BuyerName (e.item.cells(2)), the Order# (e.item.cells(1)), and a handle to the checkbox created above.  Then create a list item with the row data and check the listbox if it exists.  If so, turn the checkbox "checked" property on.

Now to handle the checkbox "checkedchanged event...

Private Sub OnCheckedChangedEvent(ByVal sender As Object, ByVal e As System.EventArgs) 

  Dim griditem As DataGridItem
  Dim livalue As String
  Dim liText As String
  Dim cb As CheckBox
  Dim litem As ListItem
  For Each griditem In DataGrid1.Items 
    liText = DataGrid1.Items(griditem.ItemIndex).Cells(2).Text.ToString 
    livalue = DataGrid1.Items(griditem.ItemIndex).Cells(1).Text.ToString
    cb = CType(griditem.Cells(0).Controls(0), CheckBox)
    litem = New ListItem(liText, livalue)
    If cb.Checked Then
      If Not ListBox1.Items.Contains(litem) Then
        ListBox1.Items.Add(litem)
      End If
    Else
      If ListBox1.Items.Contains(litem) Then
        ListBox1.Items.Remove(litem)
      End If
    End
    If litem = Nothing
  Next

End Sub

When a checkbox is checked, this sub loops through all the displayed items in the grid and determines the status of the checkbox and makes the appropriate changes in the listbox on the page.  You can also use an array stored in the session object or the viewstate as well.  With a slight change to the OnCheckedChangedEvent, you can limit the number of items selected:

Private Sub OnCheckedChangedEvent(ByVal sender As Object, ByVal e As System.EventArgs) 

  Dim griditem As DataGridItem
  Dim livalue As String
  Dim liText As String
  Dim cb As CheckBox
  Dim litem As ListItem 
  Dim chkCountLimit as Int32 = 5 
  For Each griditem In DataGrid1.Items 
    liText = DataGrid1.Items(griditem.ItemIndex).Cells(2).Text.ToString 
    livalue = DataGrid1.Items(griditem.ItemIndex).Cells(1).Text.ToString
    cb = CType(griditem.Cells(0).Controls(0), CheckBox)
    litem = New ListItem(liText, livalue)
    If cb.Checked Then
      If Not ListBox1.Items.Contains(litem) Then
        If ListBox1.Items.Count < chkCountLimit Then
          ListBox1.Items.Add(litem)
        Else
          cb.Checked = False 
        End If
      End If
    Else
      If ListBox1.Items.Contains(litem) Then
        ListBox1.Items.Remove(litem)
      End If
    End
    If litem = Nothing
  Next

End Sub

If the limit of checkboxes is matched, the checkbox is turned back off.

That's it.  This will maintain the checkbox selection across the paging and sorting of the grid. Other things that can be done would be to hide all the unchecked ckeckboxes when the limit has been met and/or a checkbox to turn on all visible items in the grid.  If there is enough interest, I will write an article on that subject in the future.

© 2003 by Kool Software
All Rights Reserved