I have a need to print
out some documents programmatically using .Net and C#.
This document just goes
over the a few specific features Selecting a printer to print to. Printing more copies, setting the portrait or
landscape, and printing ranges.
Set up a Virtual Printer
Before I starting
writing this program I downloaded and installed a virtual printer. In the past I have used a CUPS printer on my
Mac but for this time around I looked around for something to run directly on
my Windows 7 machine. I found CutePDF at
http://www.cutepdf.com/Products/CutePDF/writer.asp [1]
I installed this virtual
server so I could test my printing without using up so much paper.
Create a basic Windows Form Application
From Visual Studio 2012
Professional click on New project (or from the menu select File --> New --> Project
- Select Windows Forms Application
- I named mine PrinterListTestApp
- Click OK
In the Toolbox search
for "print" the PrintDocument
and PrintPreviewControl will be displayed
Drag the PrintDocument
and PrintPreivewControl on the the Form.
Double click on the
PrintDocument1
This will open the
PrintPageEventArgs method for this document
Here is the code I wrote for the document creation
private void printDocument1_PrintPage(object sender,
Font font = new Font("Microsoft
Sans Serif", 48F,
System.Drawing.FontStyle.Bold,
System.Drawing.GraphicsUnit.Point,
((byte)(0)));
Graphics g = e.Graphics;
g.DrawString("Print
Me",
font,
System.Drawing.Brushes.Black, 100, 50);
}
|
I resized the form a bit
and resized the PrintPreviewControl and resize it slightly
From the
PrintPreviewControl properties set the Document Property to the printDocument1
Run the program by
clicking start
The program shows the
print preview for this document.
Add a "Print"
button to the form
private void button1_Click(object sender, EventArgs e) {
this.printDocument1.Print();
}
|
Here is the code to
print the document.
Run the program and click
Print
This will print to your
default printer, so how do we select
which printer to print to?
First get the list of printer
Add a combo box to
the form
namespace PrinterListTestApp {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
String defaultPrinter = (new
System.Drawing.Printing.
PrinterSettings()).PrinterName;
foreach (string printer in System.Drawing.Printing.
PrinterSettings.InstalledPrinters)
{
comboBox1.Items.Add(printer);
if(printer.Equals(defaultPrinter)){
comboBox1.SelectedItem =
printer;
}
}
}
|
Here is the code I added to add the list of printers to the
combo box.
System.Drawing.Printing.PrinterSettings.InstalledPrinters
Will return a list of the installed printers.
(new System.Drawing.Printing.PrinterSettings()).PrinterName
Will get the name of the current default printer.
Run the program
Here you can see it selected my default printer the "Cute
PDF Writer"
If I pull down the list you can see all my printers
Now that there is a combo box the code needs to be updated to
print to the selected printer.
private void button1_Click(object sender, EventArgs e) {
this.printDocument1.PrinterSettings.PrinterName
=
comboBox1.SelectedItem.ToString();
this.printDocument1.Print();
}
|
Run the program again
Select a printer that is not the default printer and click
print.
It should print to the printer you selected
Printing more copies
Add A NumericUpDown to the Form (and a label)
Set the Value property to 1 of the NumericUpDown
I also set its minimum to 1
A simple solution is to just add a loop
private void button1_Click(object sender, EventArgs e) {
for (int x = 0; x < numericUpDown1.Value; x++) {
this.printDocument1.PrinterSettings.PrinterName
=
comboBox1.SelectedItem.ToString();
this.printDocument1.Print();
}
}
|
This worked out fine for me
There seems to be a better way to do it according to http://msdn.microsoft.com/en-us/library/system.drawing.printing.printersettings.copies.aspx
[2]
Where you can just set the Copies property like so
private void button1_Click(object sender, EventArgs e) {
this.printDocument1.PrinterSettings.PrinterName
=
comboBox1.SelectedItem.ToString();
this.printDocument1.PrinterSettings.Copies
= (short)numericUpDown1.Value;
;
this.printDocument1.Print();
}
|
But this would not work for me, and I am not really sure
why. There is a note from Microsoft saying
"Some printers might not support printing more than one copy at a
time."
So I am at a loss for the time
being I am stuck using loops
Printing Landscape or Portrait
Put a few radio buttons inside a GroupBox
Double click on the radio buttons to create their CheckChanged
events
private void radioButton1_CheckedChanged(object sender,
EventArgs e) {
if (radioButton1.Checked) {
this.printDocument1.DefaultPageSettings.Landscape
=
false;
this.printPreviewControl1.InvalidatePreview();
this.printPreviewControl1.AutoZoom = true;
}
}
private void radioButton2_CheckedChanged(object sender,
EventArgs e) {
if (radioButton2.Checked) {
this.printDocument1.DefaultPageSettings.Landscape
= true;
this.printPreviewControl1.InvalidatePreview();
this.printPreviewControl1.AutoZoom
= true;
}
}
|
Here is the code I came up with that will change the PrintPreview from landscape to portrait and
resize it to fit.
Run the program
That works well, but still does not print it out correctly.
private void button1_Click(object sender, EventArgs e) {
if (radioButton2.Checked) {
this.printDocument1.DefaultPageSettings.Landscape
=
radioButton2.Checked;
}
for (int x = 0; x < numericUpDown1.Value; x++) {
this.printDocument1.PrinterSettings.PrinterName
=
comboBox1.SelectedItem.ToString();
this.printDocument1.Print();
}
}
|
I updated the print code to the following so it will print
in landscape or portrait, whichever is selected.
At this point the Generating Preview dialog that pops up
real quickly whenever I change the page orientation is driving me a little
batty.
It looks like it's easier said than done. I did find this page http://anotherdeveloper.blogspot.com/2012/01/how-to-hide-net-printpreviewcontrols.html
[3] that looked promising but as I am crunched for time at the moment I guess I
have to skip fixing this for now.
Printing Ranges
How do you only print pages 2, 4, and 6 of a document?
First I need to update my code to print out 10 pages.
namespace PrinterListTestApp
{
public partial class Form1 : Form {
private int currentPage = 1;
public Form1() {
InitializeComponent();
String defaultPrinter = (new
System.Drawing.Printing.
PrinterSettings()).PrinterName;
foreach (string printer in System.Drawing.Printing.
PrinterSettings.InstalledPrinters)
{
comboBox1.Items.Add(printer);
if(printer.Equals(defaultPrinter)){
comboBox1.SelectedItem =
printer;
}
}
}
private void printDocument1_PrintPage(object sender,
System.Drawing.Printing.PrintPageEventArgs e) {
Font font = new Font("Microsoft
Sans Serif", 48F,
System.Drawing.FontStyle.Bold,
System.Drawing.GraphicsUnit.Point,
((byte)(0)));
Graphics g = e.Graphics;
if (this.currentPage < 11) {
g.DrawString("Page " + this.currentPage, font,
System.Drawing.Brushes.Black, 100, 50);
this.currentPage++;
e.HasMorePages = true;
}
if (this.currentPage > 10) {
currentPage = 1;
e.HasMorePages = false;
}
}
|
Add another NumericUpDown Spinner to display different Pages
in the Preview.
Double click on the new spinner to open its Value Changed
event
private void numericUpDown2_ValueChanged(object sender,
EventArgs e) {
printPreviewControl1.StartPage
= (short) numericUpDown2.Value - 1;
}
|
This code will update the preview page when the spinner number
changes.
Run the program and test it
As you change the page numbers you change the page number
being previewed.
Add a couple of NumericUpDown spinners to allow a range to
be set.
private void button1_Click(object sender, EventArgs e) {
if (radioButton2.Checked) {
this.printDocument1.DefaultPageSettings.Landscape
=
radioButton2.Checked;
}
for (int x = 0; x < numericUpDown1.Value; x++) {
this.printDocument1.PrinterSettings.PrinterName
=
comboBox1.SelectedItem.ToString();
this.printDocument1.PrinterSettings.PrintRange
= PrintRange.SomePages;
this.printDocument1.PrinterSettings.FromPage
= (short)
numericUpDown3.Value;
this.printDocument1.PrinterSettings.ToPage
= (short)numericUpDown4.Value;
this.printDocument1.Print();
}
}
|
Here is the updated code.
The PrintRange must be set to SomePages.
Then the FromPage and ToPage must be set.
Run the program
Set a range that is a subset
And if I print it out… it prints them all out. So that did not work.....
I think I finally get it
It took me a while but I think I finally get it. Setting a PrintDocuments FromPage does not do
anything magical it just stores a value that can be retrieved from the
PrintPageEventArgs.
With that in mind here is an update to my code
private void printDocument1_PrintPage(object sender,
System.Drawing.Printing.PrintPageEventArgs e) {
Font font = new Font("Microsoft
Sans Serif", 48F,
System.Drawing.FontStyle.Bold,
System.Drawing.GraphicsUnit.Point,
((byte)(0)));
Graphics g = e.Graphics;
//Set the currentPage to the FromPage
if (this.currentPage == 1 &&
e.PageSettings.PrinterSettings.PrintRange
==
PrintRange.SomePages) {
this.currentPage =
e.PageSettings.PrinterSettings.FromPage;
}
if (this.currentPage < 11) {
g.DrawString("Page " + this.currentPage, font,
System.Drawing.Brushes.Black, 100, 50);
this.currentPage++;
e.HasMorePages = (this.currentPage <
11)
&& this.currentPage <
e.PageSettings.PrinterSettings.ToPage
+ 1;
}
if (!e.HasMorePages) {
currentPage = 1;
}
}
|
Now it prints out the range of pages I am expecting.
The same idea would go for storing the number of copies to
print out. You could handle it all in
the PrintPageEventArgs.
References
Accessed 05/2013
[2] PrinterSettings.Copies
Property
Accessed 05/2013
[3] How-to Hide the .NET
PrintPreviewControl's "Generating Previews" Dialog
Accessed 05/2013
Hello could you show how a simple form of
ReplyDeleteprint some text, for example in the form I create
panel, this panel I enter any text you choose size
text and send the print button (Print)
Printing only a Panel is a bit of work, but I did find a tool PrintForm for printing an entire form and I made a Blog post on it at
Deletehttp://www.whiteboardcoder.com/2013/08/printing-with-printform.html
Hopefully that is something you can use.