Steps to Implement Paging in a DataGrid
When you start a WebForms project in Visual Studio, the first thing you’ll do is drag a DataGrid onto your page. Open the toolbox, find the WebForms section, and drop the <asp:DataGrid> onto the designer surface. Switching to the HTML view instantly shows a minimal tag:
<asp:DataGrid id="DataGrid1" runat="server"></asp:DataGrid>
That alone won’t give you paging, but it’s the foundation. From the designer, click the DataGrid, then open the Properties window. Here you can set the visual style - border, cell padding, fonts - while keeping the focus on functionality. Enable paging by checking AllowPaging. This flag tells the framework to render navigation controls (Next, Previous, page numbers) at the bottom of the grid.
Next, decide how the columns should appear. By default, a DataGrid auto‑generates columns based on the data source. If you set AutoGenerateColumns to False, you’ll manually define each column in markup. This gives you more control: you can hide internal identifiers, rename headers to something user‑friendly, or set column widths. For example, you might bind a column to DOC NUMBER but display it simply as “Doc #”. In the Properties window, you can toggle Visible on individual columns after you’ve added them.
Now, you must hook up an event that fires whenever a user clicks a pager link. In Visual Studio’s designer, there is no automatic way to add the OnPageIndexChanged attribute, so you have to switch back to the HTML view and type it yourself:
OnPageIndexChanged="myDataGrid_PageChanger"
Without this attribute, the DataGrid will render the pager controls but clicking them will do nothing. The event name you provide must match a method defined in your code‑behind file. Keep the naming consistent: the method should be public or protected, accept two parameters - object source and DataGridPageChangedEventArgs e - and perform two simple steps: update the grid’s CurrentPageIndex to e.NewPageIndex, then refresh the data.
Because paging is a client‑side request that changes the data shown, you usually call a separate RefreshGrid method that re‑retrieves data from your database and re‑binds it. The method should follow a clean pattern: open a connection, build a SQL query that includes an ORDER BY clause, execute it via a SqlDataAdapter, fill a DataSet, assign that DataSet to DataGrid1.DataSource, and finally call DataBind. When you re‑bind, the DataGrid automatically knows to show the correct page because CurrentPageIndex was just updated.
At this point, your DataGrid will display the first page of results and let the user navigate through subsequent pages with a simple “Previous” and “Next” button set. The markup might look verbose, but each attribute serves a purpose. The PagerStyle section, for instance, lets you change the font, background color, or even use custom text for the next and previous buttons. Visual Studio’s auto‑generation of the property tags can save time, but hand‑editing gives you the flexibility to match corporate styling guidelines or design system standards.
Keep in mind that the DataGrid’s paging operates on the entire data set retrieved from the database. If you’re working with thousands of rows, the grid fetches them all on each page change, which can become a performance bottleneck. That scenario will be covered in the next section, where we’ll walk through the code that pulls data into the grid and then discuss strategies to keep the UI snappy even when the underlying data set is huge.
Understanding the Code Behind Paging
The event handler that drives paging is short but critical. In the code‑behind file, you’ll write something like:
Protected Sub myDataGrid_PageChanger(ByVal source As Object, ByVal e As DataGridPageChangedEventArgs)
DataGrid1.CurrentPageIndex = e.NewPageIndex
RefreshGrid()End Sub
When the user clicks a pager button, the framework creates a DataGridPageChangedEventArgs object that carries the index of the page the user requested. The handler reads that index and updates the grid’s CurrentPageIndex property. Immediately after, it calls RefreshGrid, which re‑executes the data retrieval logic. Because the grid knows which page to show, DataBind will only render the rows that belong to that page, not the entire data set. This separation of concerns keeps the paging logic clean: the event handler simply translates a user action into a state change, and the data layer takes care of fetching the right rows.
The RefreshGrid routine itself encapsulates all database access details. A typical implementation might look like this:
Private Sub RefreshGrid()
Dim strState As String = "AL"
Dim strConnect As String = GetConnectString()
Dim strSQL As String = "SELECT Docket_ID AS [ID], Docket_Number AS [DOC NUMBER], Docket_Title AS [TITLE] FROM dbv_Docket WHERE State_Code = @State ORDER BY Docket_Number"
Using Conn As New SqlConnection(strConnect)
Dim AdapterDockets As New SqlDataAdapter(strSQL, Conn)
AdapterDockets.SelectCommand.Parameters.AddWithValue("@State", strState)
Dim DataSetDockets As New DataSet()
AdapterDockets.Fill(DataSetDockets)
DataGrid1.DataSource = DataSetDockets
DataGrid1.DataBind()
End UsingEnd Sub
Notice how the SQL string is parameterized to avoid injection attacks, even though the state code is hard‑coded for this example. The SqlDataAdapter fills a DataSet with all rows that match the query. That DataSet becomes the data source for the DataGrid, and calling DataBind instructs the grid to render the appropriate page of rows. If you had set AutoGenerateColumns to False, the columns defined in markup would be used instead of automatic mapping.
This code illustrates a classic pattern in WebForms: a tight coupling between the UI and the data layer. While the approach works well for small to medium data sets, it begins to strain resources as the number of rows grows. In the next section, we’ll explore how to keep this pattern efficient and discuss alternatives that let you fetch only the rows needed for the current page.
Performance Considerations with Large Data Sets
Imagine the DataGrid pulls 100,000 records from the database each time a user requests a page. The first request populates the grid with all rows, then the user clicks “Next” and the grid retrieves the same 100,000 rows again, just to shift the view to a different slice. That repeated round‑trip can slow the user interface and increase server load unnecessarily. In many production scenarios - especially in enterprise telecom applications - the dataset can be in the millions, making full retrieval untenable.
To mitigate this, most developers turn to server‑side custom paging. Instead of letting the DataGrid handle pagination after fetching the entire dataset, you write SQL that returns only the rows for the requested page. In SQL Server 2012 and later, the easiest approach uses the OFFSET … FETCH clause:
SELECT Docket_ID AS [ID], Docket_Number AS [DOC NUMBER], Docket_Title AS [TITLE]FROM dbv_DocketWHERE State_Code = @StateORDER BY Docket_NumberOFFSET @Skip ROWS FETCH NEXT @Take ROWS ONLY
Here, @Skip is (CurrentPageIndex * PageSize) and @Take is PageSize. By passing these parameters to the query, the database engine returns only the subset of rows needed for the current page. The DataGrid then binds to that smaller result set, dramatically reducing memory consumption and network traffic.
Another approach is to use a SqlDataSource control with the CommandText property set to a stored procedure that accepts page size and index as parameters. The stored procedure returns a total count of rows so the DataGrid can calculate how many pages exist, and it returns only the slice of data requested. This method keeps the paging logic in the database layer, which is efficient for large tables.
Regardless of the technique, the key is to let the database do the heavy lifting. The DataGrid itself should remain a thin presentation component that receives a ready‑made set of rows and displays them. By implementing custom paging, you eliminate the double‑fetch problem and keep the user experience responsive. If your application requires sorting or filtering, combine those operations in the same stored procedure or query to avoid pulling unnecessary rows into application memory.
Beyond the code, consider caching strategies. Frequently accessed pages can be stored in a distributed cache such as Redis or in a session variable for the duration of the user’s browsing session. This can further reduce database load for users who bounce back and forth between pages. However, caching introduces complexity in invalidation: if the underlying data changes, you must refresh or purge the cached entries to avoid stale data.
In summary, paging with a DataGrid is straightforward when the dataset is small, but for real‑world applications you’ll need to implement server‑side paging, parameterized queries, and possibly caching. The goal is to fetch only what the user needs, keep the UI fluid, and reduce the strain on the server and database.





No comments yet. Be the first to comment!