What is the best way to print stuff from c#/.net?
The question is in regard to single pages as well as to reports containing lots of pages.
It would be great to
» Sample Code to show basics of Printing in Windows Forms Applications:
using System.Drawing.Printing;
PrintDocument printDoc = new PrintDocument();
printDoc.DefaultPageSettings.Landscape = true;
printDoc.DefaultPageSettings.Margins.Left = 100; //100 = 1 inch = 2.54 cm
printDoc.DocumentName = "My Document Name"; //this can affect name of output PDF file if printer is a PDF printer
//printDoc.PrinterSettings.PrinterName = "CutePDF";
printDoc.PrintPage += new PrintPageEventHandler(printDoc_PrintPage);
PrintDialog printDialog = new PrintDialog();
printDialog.Document = printDoc; //Document property must be set before ShowDialog()
DialogResult dialogResult = printDialog.ShowDialog();
if (dialogResult == DialogResult.OK)
{
printDoc.Print(); //start the print
}
void printDoc_PrintPage(object sender, PrintPageEventArgs e)
{
Graphics g = e.Graphics;
string textToPrint = ".NET Printing is easy";
Font font = new Font("Courier New", 12);
// e.PageBounds is total page size (does not consider margins)
// e.MarginBounds is the portion of page inside margins
int x1 = e.MarginBounds.Left;
int y1 = e.MarginBounds.Top;
int w = e.MarginBounds.Width;
int h = e.MarginBounds.Height;
g.DrawRectangle(Pens.Red, x1, y1, w, h); //draw a rectangle around the margins of the page, also we can use: g.DrawRectangle(Pens.Red, e.MarginBounds)
g.DrawString(textToPrint, font, Brushes.Black, x1, y1);
e.HasMorePages = false; //set to true to continue printing next page
}
It depends a lot on the requirements of your application.
Even though it isn't the perfect tool (really far from that), Crystal Reports tends to be a good choice. It gives you the option of getting data directly from a Database or, if you already have a list of objects you want to print, you can pass them to the document and bind the object properties to the labels of the report.
But give us some more information of what you're trying to do, so you can receive better proposals.
We used a set of third party DLLs from PDFSharp who in turn use DLLs from MigraDoc. I'm not privy to all the reasons that we went that direction (the decision was made by a senior developer), but I can tell you that:
I use the standard libraries such as System.Diagnostics.ProcessStartInfo to use Adobe Acrobat to print a pdf. The end user will not have to interact with the Acrobat GUI, though, annoyingly, the following code still pulls it on-screen for a few seconds.
// Sample fileName = System.Environment.GetFolderPath(
// System.Environment.SpecialFolder.CommonApplicationData)
// + @"\MyCompany\MyProject\TestPrint.pdf"
private void SendPrintJob(string fileName)
{
try
{
// Start by finding Acrobat from the Registry.
// This supposedly gets whichever you have of free or paid
string processFilename = Microsoft.Win32.Registry.LocalMachine
.OpenSubKey("Software")
.OpenSubKey("Microsoft")
.OpenSubKey("Windows")
.OpenSubKey("CurrentVersion")
.OpenSubKey("App Paths")
.OpenSubKey("AcroRd32.exe")
.GetValue(String.Empty).ToString();
ProcessStartInfo info = new ProcessStartInfo();
info.Verb = "print";
info.FileName = processFilename;
info.Arguments = String.Format("/p /h {0}", fileName);
info.CreateNoWindow = true;
info.WindowStyle = ProcessWindowStyle.Hidden;
info.UseShellExecute = false;
Process p = new Process();
p.StartInfo = info;
p.Start();
p.WaitForInputIdle();
// Recommended to add a time-out feature. Mine is coded here.
}
catch (Exception e)
{
Console.WriteLine("Error sending print job. " + e.Message);
}
I did not read document manipulation into the OP, but I see other answers commenting on the fact. A few StackOverflow Q&As from 2008-2012 (including @Robert Gowland from this question) say that PDFSharp / MigraDoc have poor documentation.
In 2018, I have found it to be an easy learning curve, with many samples at the homepage. I read this question this morning to figure out how to print a graph, and now have a button to screen-shot my application and print.
You will want to go to NuGet package manager for PDFsharp-MigraDocs
(or PDFsharp-MigraDocs-WPF
, or PDFsharp-MigraDocs-GDI
). MigraDocs is the high-level component that can create documents from elements, without care of if they are pdf or image or what have you. PDFSharp is the component that helps to, i.e., rearrange documents, put multiple documents on a page, and break apart content from one to two pages.
If you can build your output as a FlowDocument, you can turn it into XPS easily to get an "electronic" version, and the print the XPS.
For reports, I use the RDLC control.
For everything else, I use the inherent printing objects within .NET.
Edit The inherent printing objects are all found in the System.Drawing.Printing namespace. When you use the PrintDialog or the PrintPreviewDialog in a WinForms (or WPF) application, it is to these objects that you're turning over control.
The fundamental concept is that you're drawing to the printer. The simplest form of this is:
Sub MyMethod()
Dim x as New PrintDocument
AddHandler x.PrintPage, AddressOf printDoc_PrintPage
x.Print
End Sub
Sub printDoc_PrintPage( sender as Object, e as PrintPageEventArgs)
Dim textToPrint as String= ".NET Printing is easy"
dim printFont as new Font("Courier New", 12)
dim leftMargin as int= e.MarginBounds.Left
dim topMargin as int = e.MarginBounds.Top
e.Graphics.DrawString(textToPrint, printFont, Brushes.Black, leftMargin, topMargin)
End Sub
What's happening here is that when my object (x) is sent the print command, it raises the "PRINT PAGE" event (which is designed to print 1 page at a time). This event then uses the Graphics attribute of the PrintPageEventArgs to draw the relevant string directly to the print spooler.
Here's one tutorial, and a quick Google search for ".NET printing tutorial" returns a bit over 200K results.