|
The subject of this blog should say it all. I've searched everywhere for a solution to this, to no avail. Essentially, what I wanted to do is this: I needed to present a paged, filtered DataGrid to a user, with checkboxes added programmatically, and maintain the state of the checkboxes as PostBacks occurred.
There were tons of articles on how to programmatically add a checkbox to a DataGrid, which I had already figured out how to do. One way to do this (very inefficiently) is:
Stash the DataSet, DataView and DataGrid on the Session so it can be pulled after PostBacks. Then, iterate thru the DataGrid, then nest thru the DataSet, and set a Boolean value on the DataSet to match the value of the checkbox. So, you're looping thru the grid grid.Items.Count times, and for every item in the grid, you're looping thru the DataSet ds.Tables(”Table”).Rows.Count times. And that's just to capture the checkboxes.
As the user returns to that page of the grid, you'll need to pull the DataView off the Session, evaluate a column in the DataView against a column in the e.Items collection (from the DataGridItemEventArgs in the ItemCreated() event handler), and “check“ the box accordingly. Again, this is nested looping at it's worst.
This worked, but as I paged through, or as I changed the RowFilter on the dataview, the performance was horrible. I'm not know for writing efficient code, but this was ridiculous.
Make 'em sick, make 'em well.
So, after I filled my DataSet, I loaded my unique compare column (from the DataSet) along with a True/False value into a Collection. Since the Collection.Items() collection is read-only, I had to create a basic Class that exposed a property “CheckState“ to return True or False. That way, when I wanted to modify the value of the item in the collection for the given key, I could just modify a reference to the CheckState object. There will be code snippets below, btw.
So by now on PageLoad, I've got a filled DataSet, and a Collection representing key information. I stash that onto the Session, and I wait for a PostBack. When I get the PostBack, I loop thru the DataGrid, check the state of the checkboxes, and updating the collection accordingly. Again, stashing it back to the Session when I'm done.
When the page or RowFilter changes, I need to re-check checkboxes as necessary. I plugged into the ItemCreated event handler, and used the e.Items collection to fetch my key value, and I compared it to the Item in the Collection. If True, check the box.
Below is the code that I used to do all this (variable and table names have been changed to protect their anonymity).
Reply to this blog or email me if you wanna talk about it.
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim lcv As Integer Dim cb As CheckBox Dim ds As DataSet Dim oState As CheckState If IsPostBack Then ' pull the collection off the Session m_Collection = Session("Collection") For lcv = 0 To dg.Items.Count - 1 ' get a checkbox object from the datagrid to evaluate cb = dg.Items(lcv).Cells(0).Controls(0) ' get the StateCheck object reference from the collection ' that matches the key column from the datagrid oState = m_Collection.Item(dg.Items(lcv).Cells(1).Text) ' update the referenced object (which should update the collection) If cb.Checked Then oState.State = True Else oState.State = False End If ' now that we've updated, push the collection back to Session Session("Collection") = m_Collection Next Exit Sub End If PopulateGrid() End Sub
Private Sub PopulateGrid() Dim oDR As SqlDataReader Dim parmPostNum As SqlParameter Dim parm As SqlParameter Dim tableNames(0) As String Dim iCompanyID As Int32 Dim dvPostMembers As DataView Dim lcv As Integer Dim lcv2 As Integer Dim cb As CheckBox Dim iCardNumber As Integer Dim oState As Integer ... ' Fill the DataSet here ...
m_Collection = New Collection
' set all to False, and add to the collection
For lcv = 0 To ds.Tables("Table").Rows.Count - 1 ds.Tables("Table").Rows(lcv).Item("CheckBoxChecked") = False oState = New CheckState oState.State = False m_Collection.Add(oState, ds.Tables("Table").Rows(lcv).Item("KeyValue")) Next
Session("Collection") = m_Collection
dv = New DataView(ds.Tables("Table")) dv.RowFilter = "Column='filter'" Session("DataView") = dv Session("DataSet") = ds dg.DataSource = dv
dg.DataBind()
End Sub
Private Sub dg_ItemCreated(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs) Handles dg.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 dv As DataView Dim keyval As String Dim oState As CheckState
dv = Session("DataView") keyval = dv.Item(e.Item.ItemIndex).Row.Item(13) ' pull the collection off the Session m_Collection = Session("Collection")
' get the CheckState of the current item in the data view oState = m_Collection.Item(keyval) cb.Checked = oState.State cb.EnableViewState = True cb.ID = "chkItemChecked" cb.AutoPostBack = False cell.HorizontalAlign = HorizontalAlign.Right cell.Controls.Add(cb) End Sub
Public Class CheckState Private m_bCheckState As Boolean Public Property State() As Boolean Get Return m_bCheckState End Get
Set(ByVal Value As Boolean) m_bCheckState = Value End Set
End Property End Class
|