The Datagrid component is one of the most useful features in ASP.NET when it comes to displaying data on screen. There are many aspects which can be customised easily including pagination, sorting and filtering of data.

However when it comes to printing out that datagrid, you suddenly find the data half cut off on the bottom of the page and no nice headers at the top of the next page!
So how do you make ASP.NET put "proper" breaks between printed pages, with headers at the top of each new page?
ANSWER: You use the CSS "page-break-before" property.
According to the W3C "The page-break-before property sets the page-breaking behavior before an element." so if there isn't enough remaining room on the printed page for the element in question a form-feed is issued before printing the item.
To use this feature in a datagrid requires inserting "dummy" rows in the grid when populating the data. These dummy rows are inserted at set intervals in your data, the intervals matching the height of your pape, so when the datagrid is printed out as the dummy rows are reached, a page-break is thrown.
To avoid these dummy lines being seen on-screen they are placed in a "print-only" stylesheet. In addition to inserting a page-break command, it is possible to add additional rows underneath to reproduce the page titles, so each time a page-break is thrown the datagrid titles are printed at the top of each page:

So how is this done?
First we populate a datagrid in the usual way - here I am using a webservice:
consumeWebService = New MyWebServices.DataRoutines
Try
ds = consumeWebService.ReadCustomers(strCustNo)
Catch e As Exception
'No records returned
End Try
MyDataGrid.DataSource = ds
MyDataGrid.DataBind()
Now we have our datagrid full of data, we declare a couple of objects which will allow us to modify the contents:
Dim row As DataGridItem
Dim cell As TableCell
The following code inserts a new row at the TOP of the *already filled* datagrid:
'First build up the row structure - this could consist of many columns but here we have only one
row = New DataGridItem(-1, -1, ListItemType.Separator)
cell = New TableCell
cell.Text = "Customer Report for This Month"
row.Cells.Add(cell)
'The following line allows us to insert the row ANYWHERE we want - in this case at row "0"
MyDataGrid.Controls(0).Controls.AddAt(0, row)
We could also have inserted the row at the END of the datagrid by simply calling the Add method rather than AddAt:
MyDataGrid.Controls(0).Controls.Add(row)
Now we get down to the serious business of inserting the page-breaks. What we are doing is effectively stepping through the datagrid rows (in this case 32 at a time), inserting a new page-break row each time:
Dim nRow As Int16
nRow = 0
Dim intPageNo = 1
Do While nRow <= Datagrid3.Items.Count
nRow = nRow + 32
If nRow < Datagrid3.Items.Count Then
row = New DataGridItem(-1, -1, ListItemType.Separator)
nbsp;cell = New TableCell
cell.Text = "<hr style=""PAGE-BREAK-AFTER: always"" >"
row.Cells.Add(cell)
'Finally insert the new page-break row..
Datagrid3.Controls(0).Controls.AddAt(nRow, row)
end if
loop
The page-break style will have no effect on the screen-view of the datagrid, but will paginate nicely when printed out. You will of course have to experiment to get the right number of rows per paper/printer size!