|
Some time ago, the company I work for was quoting on a rewrite project from Java to .NET. One of their requirements was the ability to select up to two records from a datagrid that can then be compared to generate a PDF document on the fly. Well, even though we did not get the job, I did come up with a nice way to do exactly what they asked for. The finished grid looks something like the one below:

This datagrid has a bunch of some very advanced features such as "Reversible Sorting", "Customized Pager", "Customized Footer", and the almighty "Checkbox Validation". This article will focus on the Checkbox Validation only.
The Setup
Private Sub DataGrid1_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs) Handles DataGrid1.ItemDataBound '///////// Add CheckBoxes //////////// 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 cell.Controls.Add(cb) 'add event handler that will fire the validation AddHandler cb.CheckedChanged, AddressOf OnCheckedChangedEvent End Sub
First we need to add a checkbox for every item (row) in the datagrid. This is done within the ItemDataBound event that fires for every item created. Also, make sure to add an event handler, in this case called OnCheckedChangedEvent. This event will be responsible for running the required validation subroutines. Make sure to check for the ListItemType when adding the checkbox as shown above.
Storing Selections in the View State
Private Sub OnCheckedChangedEvent(ByVal sender As Object, ByVal e As EventArgs) 'CheckBox Event Handler 'first delete IDs 'then if counter WAS less than 2, add ID, else remove ID 'then validate again to produce listbox & checkboxes
RemoveIDFromListBox()
If CheckBoxCount < 2 Then AddIDToListBox() Else RemoveIDFromListBox() End If 'now check the once that have been checked previously ValidateCheckBoxes()
End Sub
Private Sub AddIDToListBox()
Dim dgi As DataGridItem Dim chkText As String Dim chkValue As String Dim cb As CheckBox
For Each dgi In DataGrid1.Items
chkText = DataGrid1.Items(dgi.ItemIndex).Cells(1).Text.ToString chkValue = DataGrid1.Items(dgi.ItemIndex).Cells(1).Text.ToString cb = CType(dgi.Cells(0).Controls(0), CheckBox)
If cb.Checked Then
Dim litem As New ListItem() litem.Text = chkText.ToString litem.Value = chkValue.ToString
If Not ListBox1.Items.Contains(litem) Then ListBox1.Items.Add(litem) CheckBoxCount = CheckBoxCount + 1 If CheckBoxCount >= 2 Then HideRemainingCheckBoxes = True End If End If End If Next
End Sub
Private Sub RemoveIDFromListBox()
Dim dgi As DataGridItem Dim chkValue As String Dim chkText As String Dim cb As CheckBox
For Each dgi In DataGrid1.Items
chkText = DataGrid1.Items(dgi.ItemIndex).Cells(1).Text.ToString chkValue = DataGrid1.Items(dgi.ItemIndex).Cells(1).Text.ToString cb = CType(dgi.Cells(0).Controls(0), CheckBox)
If Not cb.Checked Then
Dim litem As New ListItem() litem.Text = chkText.ToString litem.Value = chkValue.ToString
If ListBox1.Items.Contains(litem) Then ListBox1.Items.Remove(litem) CheckBoxCount = CheckBoxCount - 1 HideRemainingCheckBoxes = False End If End If Next
End Sub
Okay! Wow! Lot's of code. But no worries. It's half-as-much as it looks like. The OnCheckedChangedEvent will handle the following routines:
AddIDToListBox [this is the one adding the checkbox values to the ListBox (I'll explain later)]
RemoveIDFromListBox [this one removes ALL check-marks from the checkboxes]
ValidateCheckBoxes [this is the big one and we'll get to that one later]
The AddIDToListBox routine is needed to iterate through every data grid item of the data grid for one page ONLY and retrieving the values of the checkboxes IF they are checked. If the loop finds a checked checkbox, it will create a new list item and add the item (the checkbox value) to the ListBox.
The RemoveIDFromListBox routine is needed to uncheck ALL checkboxes on the current data grid page. This is necessary for the checkbox validation to work properly, otherwise it would not be possible to de-select the last remaining checkbox since the datagrid's ItemCreated event would always re-paint the checked checkbox according to its view state.
So, what exactly is happening at the OnCheckedChangedEvent? It first un-checks all checkboxes, then, in my example, it looks at the checked checkbox count (my example only two at one time are allowed to be checked), and then determines whether we have to add the last checked checkbox, or delete the last checkbox touched (checkbox event) from the ListBox.
The ListBox is crucial to all of this. It acts as out checkbox memory. You could easily use an array, session, cache, or application object to do this. You could also change the visibility attribute for the ListBox to false and it would therefore be invisible to the end-user (IE-only). This is completely up to your preference.
Validating Checkboxes
Private Sub ValidateCheckBoxes()
If HideRemainingCheckBoxes Then
Dim dgi As DataGridItem Dim cb As CheckBox Dim counter As Integer Dim counter2 As Integer Dim chkValue As String
Button1.BackColor = Color.FromName("DarkRed") Button1.ForeColor = Color.White Button1.Enabled = True
For counter = 0 To DataGrid1.Items.Count - 1 cb = CType(DataGrid1.Items(counter).Cells(0).Controls(0), CheckBox) chkValue = DataGrid1.Items(counter).Cells(1).Text.ToString 'find match For counter2 = 0 To ListBox1.Items.Count Dim litem As New ListItem() litem.Text = chkValue.ToString litem.Value = chkValue.ToString
If ListBox1.Items.Contains(litem) Then cb.Enabled = True cb.Checked = True Else cb.Enabled = False cb.Checked = False End If Next Next
Else
Dim dgi As DataGridItem Dim cb As CheckBox Dim counter As Integer Dim counter2 As Integer Dim chkValue As String
Button1.BackColor = Color.FromName("LightGrey") Button1.ForeColor = Color.Black Button1.Enabled = False
For counter = 0 To DataGrid1.Items.Count - 1 cb = CType(DataGrid1.Items(counter).Cells(0).Controls(0), CheckBox) chkValue = DataGrid1.Items(counter).Cells(1).Text.ToString 'find match For counter2 = 0 To ListBox1.Items.Count Dim litem As New ListItem() litem.Text = chkValue.ToString litem.Value = chkValue.ToString
If ListBox1.Items.Contains(litem) Then cb.Checked = True Else cb.Enabled = True cb.Checked = False End If Next Next End If ValidateListBox() End Sub
This is the Biggy! Basically what is happening here is that I first determine whether two checkboxes have already been checked or not. If not, I loop through every item of the data grid, get the check box value and compare it with the values stored in the listbox. If I find it in the listbox, I'll go ahead and check that one. If I didn't find a match, I'll keep it unchecked.
There is however, in my example a slight modification in case the checkbox counter value is greater or equal to two (two checkboxes have been checked already). In this case, I'll go through the same routine as described above. However, since I want only two checkboxes to be checked, I have to enable all other checkboxes EXCEPT the once matching with the values of the listbox.
And that's it. This is how you validate and remember checkboxes across the data grid.
The working example can be seen here: http://devspot.devspot.com/wise/Specs_Display_Grid |