During the printing (or preview) process, the PrintDocument's PrintPage event handler gets called once for each output page. But here's the tricky thing: When the PrintPage handler was called the first time, it was not to print "page 1" of the document, but to print "the first page in need of printing," whatever its page number. Search all you want through the properties of the PrintDocument class, but you will never find a PageNumber property. The PrintDocument does not know about the page numbers in your document, anddespite all of the nice things it does for youit does not care. All it knows is that you have a bunch of pages to print, and it will call your PrintPage event handler until you say "enough!"
If you turn back to Figure 19-3, you'll see that the Print dialog includes a "Page Range" section, although most of its controls are disabled by default. The PrintDialog control includes three Boolean properties that let you enable specific controls in that section: AllowCurrentPage, AllowSomePages, and AllowSelection. Setting any of these properties to True enables the matching option control. Later, after the user has made a choice, you can query the PrintDocument object's PrinterSettings.PrintRange property to determine which choice it is.
Let's add code that enables page range selection. We'll still limit the allowed pages to just those numbered one to five, but the user will be able to choose a sub-range within that set. Return to the Click event handler for the ActPrint button, and insert a few new lines of code (the ones in bold).
Private Sub ActPrint_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles ActPrint.Click ' ----- Prompt the user for printer settings, and ' start printing. UserPrinter.Document = CountingDoc UserPrinter.AllowSomePages = True CountingDoc.PrinterSettings.MinimumPage = 1 CountingDoc.PrinterSettings.MaximumPage = 5 CountingDoc.PrinterSettings.FromPage = 1 CountingDoc.PrinterSettings.ToPage = 5 If (UserPrinter.ShowDialog() = _ Windows.Forms.DialogResult.OK) Then _ CountingDoc.Print() End Sub
When the user clicks on the Print button this time, the "Print Range" section of the dialog has enabled the Pages field, and it's already filled in with the minimum and maximum pages in the range "1-5" (see Figure 19-8).
Figure 19-8. Support for page ranges
If the user adjusts this field to "1-6," an error occurs stating that the valid range is somewhere within "1-5" only. But whether the user selects "All Pages" or "1-5" or "1-4" or "2-3" or "Current Page" or "Selection," the PrintPage event handler will be called in exactly the same manner. In fact, the handler will be called dozens, even hundreds of times, until you tell it to stop. The user's selection impacts the PrinterSettings.PrintRange property and some other properties, but it does not directly impact the print process. It is up to you to alter the print behavior based on these settings.
Let's pretend that the user entered a print range of "2-3." We cannot let the PrintDocument fire the PrintPage event for all five pages because, even if we generated output for pages two and three only, we would still get three other blank pages out of the printer. What we want is to only have the event fire twice, once for page two and once for page three. We'll need to adjust the use of the WhichPage class-level tracking variable to compensate for the indicated range. First, let's change the BeginPrint handler to use the correct starting page number.
Private Sub CountingDoc_BeginPrint(ByVal sender As Object, _ ByVal e As System.Drawing.Printing.PrintEventArgs) _ Handles CountingDoc.BeginPrint ' ----- Start the counting over. WhichPage = CountingDoc.PrinterSettings.FromPage End Sub
In the PrintPage event handler, we must modify the code that determines when to quit the print process.
WhichPage += 1 If (WhichPage <= CountingDoc.PrinterSettings.ToPage) _ Then e.HasMorePages = True Else e.HasMorePages = False
Because the print preview code shares the same document settings, we need to adjust the preview code to force it to always print all pages.
Private Sub ActPreview_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles ActPreview.Click ' ----- Display a preview of the document. UserPreview.Document = CountingDoc CountingDoc.PrinterSettings.PrintRange = _ Printing.PrintRange.AllPages UserPreview.ShowDialog() End Sub
If you run the program and adjust the print range, you should get just the pages you requested. I've placed a copy of this program in the book's installation directory. You'll find it in the Print Preview Test subdirectory.