Thursday, 7 January 2010

ASP.NET: Search GridView and Programatically Select Row

On the main page of one of my apps, I have a large GridView containing a lot of rows. They're paged, but the number of pages can run to ten or twenty.

So the users needed a quick way to locate a specific item within the GridView rather than having to manually search it each time. I added an AJAX Combo Box to the page, which displays an autocomplete selector for the items which also display in the GridView. On it's SelectedIndexChanged event, I needed it to automatically select the corresponding row on the GridView.

I searched the net to find the best way to do it, but there were several problems with the solutions people had found. There's no point dwelling on those at length, but the main issue was that if you loop through a GridView's DataKeys, you only loop through the DataKeys for that specific page, not the pages which are not currently displayed. The suggested code looked like this:

For n As Integer = 0 To myGridView.DataKeys.Count - 1
If myGridView.DataKeys(n).Value = myKeyObj Then
myGridView.SelectedIndex = n
End If

That's fine if you only have one page on your GridView, but is not a lot of use when you have enabled paging and you have a requirement to search the entire data set.

A helpful person on the ASP.NET forums posted some code which allows you to loop through the pages of the GridView, so I modified it slightly and ended up with the following:

Dim i As Integer, DataSetIndex As Integer
Dim SelectedRowIndex As Integer
Dim dv As DataView = ObjectDataSourceClients.Select
Dim dt As DataTable = dv.ToTable

For i = 0 To dt.Rows.Count - 1
If dt.Rows(i)("Client_ID") = ComboBoxClientSearch.SelectedValue Then
DataSetIndex = i
Exit For
End If

GridViewAllClients.PageIndex = DataSetIndex \ GridViewAllClients.PageSize
SelectedRowIndex = DataSetIndex - (GridViewAllClients.PageSize * GridViewAllClients.PageIndex)
GridViewAllClients.SelectedIndex = SelectedRowIndex


Originally, as per the poster's code I had tried to just access the DataSet directly by using:

Dim ds As DataSet = GridViewAllClients.DataSource

This didn't work and I kept getting null reference exceptions because the GridView's DataSource is not persisted after a PostBack by the ViewState.

So in this case, I had to access the ObjectDataSource that the GridView was using, fire its Select method and convert the result to a DataTable which I could search.

That worked nicely, so I posted my findings back to the forum.

NOTE: The above code depends on the GridView and its DataSource being sorted the same way. So if you programatically sort your GridView after it's bound and then attempt to search using the above method, it won't work because the rows in the GridView and its DataSource will be out of sync.