So far we have discussed printing only an image or a single-page file. Printing multipage files is another important part of printing functionality that developers may need to implement when writing printer applications. Unfortunately, the .NET Framework does not keep track of page numbers for you, but it provides enough support for you to keep track of the current page, the total number of pates, the last page, and a particular page number. Basically, when printing a multipage document, you need to find out the total number of pages and print them from first to last. You can also specify a particular page number. If you are using the default Windows printing dialog, then you don't have to worry about it because you can specify the pages in the dialog, and the framework takes care of this for you.
To demonstrate how to do this, our next programs produces a useful printout showing all the fonts installed on your computer. This program is a useful tool for demonstrating the calculation of how many pages to print when you're using graphical commands to print.
We will use the PrintPreview facility to display the output in case you don't have access to a printer and how far down the page we are. If we're going to go over the end of the page, we drop out of the pd_PrintPage event handler and set ev.HasMorePages to true to indicate that we have another page to print.
To see this functionality in action, let's create a Windows application and add a menu with three menu items and a RichTextBox control to the form. The final form is shown in Figure 11.24.
FIGURE 11.24: A form for printing multiple pages
The Display Fonts menu display available fonts on the machine. Before we add code to this menu, we add the following variables:
- private int fontcount;
- private int fontposition = 1;
- private float ypos = 1;
- private PrintPreviewDialog previewDlg = null;
The code for the Display Fonts menu click is given in Listing 11.44. Here we read installed fonts on the system and display them in the rich text box. We use InstalledFontCollection to read all installed fonts on a machine. Then we use the InstalledFontCollection.Families property and make a loop to read all the font families. We also check if these families support different styles, including regular, bold, italic, and underline, and wee add some text to the rich text box with the current font.
LISTING 11.44: Displaying fonts
- private void DisplayFonts_Click1(object sender, Sytem.EventArgs e) {
-
- InstalledFontCollection ifc =
- new InstalledFontCollection();
-
- FontFamily[] ffs = ifc.Families;
- Font f;
-
- richTextBox1.Clear();
-
-
-
- foreach(FontFamily ff in ffs) {
- if (ff.IsStyleAvailable(FontStyle.Regular))
- f = new Font(ff.GetName(1), 12, FontStyle.Regular);
- else if (ff.IsStyleAvailable(FontStyle.Bold))
- f = new Font(ff.GetName(1), 12, FontStyle.Bold);
- else if (ff.IsStyleAvailable(FontStyle.Italic))
- f = new Font(ff.GetName(1), 12, FontStyle.Italic);
- else
- f = new Font(ff.GetName(1), 12, FontStyle.Underline);
- richTextBox1.SelectionFont = f;
- richTextBox1.AppendText(ff.GetName(1) + "\r\n");
- richTextBox1.SelectionFont = f;
- richTextBox1.AppendText("abcdefghijklmnopqrstuvwxyz\r\n");
- richTextBox1.SelectionFont = f;
- richTextBox1.AppendText("ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n");
- richTextBox1.AppendText("==========================\r\n");
- }
- }
The code for the Print Preview and Print menu items is given in Listing 11.45. This code should look familiar to you. We simply create PrintDocument and PrintPreviewDialog objects, set their properties, add a print-page event handler, and call the Print and Show methods.
LISTING 11.45: The Print Preview and Print menu items
- private void PrintPreviewMenuClick(object sender, System.EventArgs e)
- {
-
- previewDlg = new PrintPreviewDialog();
-
- PrintDocument pd = new PrintDocument();
-
- pd.PrintPage +=
- new PrintPageEventHanlder(pd_PrintPage);
-
- previewDlg.Document = pd;
-
- previewDlg.Show();
- }
-
- private void PrintMenuClick(object sender, System.EventArgs e)
- {
-
- previewDlg = new PrintPreviewDialog();
-
- PrintDocument pd = new PrintDocument();
-
- pd.PrintPage +=
- new PrintPageEventHandler(pd_PrintPage);
-
- pd.Print();
- }
The print-page event handler, pd_PrintPage, is given in Listing 11.46. We print fonts using DrawString, and we set PrintPageEventArgs.HasMorePages to true. To make sure the text fits, we increase the y-position by 60 units.
LISTING 11.46: The print-page event handler
- public void pd_PrintPage(object sender, PrintPageEventArgs ev)
- {
- ypos = 1;
- float pageheight = ev.MarginBounds.Height;
-
- Graphics g = ev.Graphics;
-
- InstalledFontCollection ifc =
- new InstalledFontCollection();
-
- FontFamily[] ffs = ifc.Families;
-
- while (ypos + 60 < pageheight &&
- fontposition < ffs.GetLength(0))
- {
-
- Font f =
- new Font(ffs[fontposition].GetName(0), 25);
-
- g.DrawString(ffs[fontposition].GetName(0), f,
- new SolidBrush(Color.Black), 1, ypos);
- fontposition = fontposition + 1;
- ypos = ypos + 60;
- }
- if (fontposition < ffs.GetLength(0))
- {
-
- ev.HasMorePages = true;
- }
- }
That's it. If we run the program, the Print menu prints multiple pages, and the Print Preview menu shows the print preview on two pages (see Figure 11.25).
As you can see, it's pretty easy to create multipage report generators. Now you can use the print option to print documents with multiple pages.
The DocumentName Property
If you want to display the name of the document you're printing, you can use the DocumentName property of the PrintDocument object:
pd.DocumentName ="A Text Document";
The new result is shown in Figure 11.26.
We have seen that using the DocumentPrintPreview class is fairly straightforward. In reality, all that's happening is that this control is passed a graphics class representing each page in a printout.
FIGURE 11.25: Print preview of multiple pages
FIGURE 11.26: Setting a document name