Tim, Peter:
The only way to get the number of pages of a custom PrintDocument is to
do a "dry run" of the entire printing process in order to determine the
page count, then do it again for real. Here is why.
From the .NET Framework's point of view, your PrintDocument is a black
box. All the Framework can do is call your OnBeginPrint following by
successive calls to OnPrintPage until OnPrintPage sets HasMorePages to
false. The outside agent doing the printing (the PrintPreviewControl,
for example) has absolutely no idea what's going on inside there, and
so has no idea how you determine which is the last page to print.
Given that, how could it ever determine, by itself, how many pages
there are to print? Since your routines are doing the page layout, your
routines are the only ones with any hope of knowing how many pages
there will be.
Peter's trick with PrintPreviewControl works only because the first
thing that PrintPreviewControl does when it displays is call your
PrintDocument object to render all of the pages. Since it's rendered
all of the pages once, it knows how many pages there are. That's why it
"knows" only when it's visible on the screen: because it's only at that
moment that it bothers to render the entire print document into visible
pages.
However, this doesn't help if you want to display "Page x of y" at the
bottom of each page. In this case, you yourself have to take a dry run
through the printing process and count the pages when you first create
an instance of your PrintDocument. Remember: your code is the only part
of the program that has any idea of what the pages look like, and
therefore how many there will be. As Nicholas said, it's up to you to
roll your own page counting algorithm. It may be as simple as counting
a particular kind of record ("one per page") or as complicated as
actually going through the motions of printing everything just to get
the page count. Whether you can take a short route depends upon how
you're laying out your data on the pages.