The title of the article is the translated Chinese title, and the original title is: Master Every Day Printing In .Net Article from Fawcette Technical Publications (www.ftponline.com) article detail 20 classes in system.drawing.printing namespaces An enumeration and 3 entrusted usage. This article will first post the original text, and finally post the complete source code, I hope to help everyone! English Original:
Listing 1 C #
Create and dispose.
The PrintDocument object exposes several events. BeginPrint is fired before any pages are actually printed, giving you the opportunity to allocate objects or open files. EndPrint occurs after the last page has been printed. Do not forget to bind the events to your PrintDocument object .
// at The Class Level
Private font bodyfont;
PRIVATE FONT HEADERFONT
Private streamreader data;
PRIVATE PRINTDocument Doc;
Private Void Mainform_Load (Object
Sender, System.EventArgs E) {
DOC = New PrintDocument ();
// shows up in print manager
Doc.documentName = "Contact List";
Doc.beginprint = new
Printeventhandler (DOC_BEGINPRINT);
Doc.endprint = New
PrinteventHandler (DOC_ENDPRINT);
}
Private void doc_beginprint (Object
Sender, Printeventargs PV) {
Data = New
StreamReader ("Contacts.csv");
Font Bodyfont = New Font ("Arial",
12);
Font Headerfont = New Font ("Arial",
twenty four);
}
Private void Doc_endprint (Object)
Sender, Printeventargs PV) {
Data.Close ();
Bodyfont.dispose ();
Headerfont.dispose ();
}
Listing 2 C #
Inherit from printdocument.
Derive A New Class from PrintDocument So You Can Encapsulate All your Printing FunctionAlity In a Single Place, Enhancing Code Reuse.
Public Class CustomPrintDocument: PrintDocument {
Private streamreader DataToprint;
Public CustomPrintDocument (StreamReader Data): Base ()
{
DataToprint = DATA;
}
Protected Override Void Onbeginprint (Printeventargs)
EV) {
Base.onbeginPrint (EV);
}
Protected Override Void OnendPrint (Printeventargs EV)
{
Base.onendPrint (EV);
}
Protected Override Void
ONQUERYPAGESETINGS (QuerypagesettingSeventArgs EV)
{
Base.onquerypageSettings (EV);
}
Protected Override Void Onprintpage (PrintPageEventArgs)
EV) {
Base.onPrintPage (EV);
Ev.graphics.drawstring ("this is a test", New
Font ("Arial", 24), Brushes.black, 100, 100);
ev.hasmorepages = false;
}
}
Listing 3 C #
Retrieve the margins with p / invoke.
The .NET Framework does not provide a way to retrieve the hard margins of a printer, so you need to use P / Invoke and call the Win32 GetDeviceCaps function. The method in this class takes a device handle (hDc), then populates the Class members with the information you need.
[DLLIMPORT ("gdi32.dll")]]]]]]
Private static extern int16 getDevicecaps ([in] [Marshalas
(UnmanagedType.u4)] int HDC, [in] [Marshalas
(UnmanagedType.u2)] INT16 FUNCT);
Private float _LEFTMARGIN = 0;
PRIVATE FLOAT _TOPMARGIN = 0;
Private float _rightmargin = 0;
Private float _bottommargin = 0;
Const short horzsize = 4;
Const short vertsize = 6;
Const short horzres = 8;
Const Short Vertres = 10;
Const Short PhysicalOffSetx = 112;
Const Short PhysicalOffSensty = 113;
Public marginfo (int devicehandle) {
FLOAT OFFX = Convert.TOSINGLE
GetDeviceCaps (DeviceHandle, PhysicalOffSetx);
FLOAT OFFY = Convert.TOSINGLE
GetDeviceCaps (DeviceHandle, PhysicalOffSety);
Float Resx = Convert.TOSINGLE
GetDeviceCaps (DeviceHandle, Horzres);
FLOAT RESY = Convert.TOSINGLE
GetDeviceCaps (DeviceHandle, Vertres);
FLOAT HSZ = Convert.TOSINGLE
GetDeviceCaps (DeviceHandle, Horzsize) / 25.4f; float vsz = convert.tosingle
GetDeviceCaps (DeviceHandle, Vertsize) / 25.4F;
FLOAT PPIX = RESX / HSZ;
FLOAT PPIY = RESY / VSZ;
_LEFTMARGIN = (OFFX / PPIX) * 100.0F;
_topMargin = (offy / ppix) * 100.0f;
_BOTTOMMARGIN = _topmargin (vsz * 100.0f);
_rightmargin = _LEFTMARGIN (HSZ * 100.0F);
}
Listing 4 C #
Lay Out The Report.
The basic format of any report must include at least a header, body, and footer section. Use Rectangle objects to lay out your reports easily. You can increase the complexity of those reports by adding more Rectangle objects.
// Create the Header
INT HeaderHeight =
Hf.getHeight (ev.graphics);
Rectanglef Header = New
Rectanglef (Left Margin, Topmargin,
PageWidth, HeaderHeight;
// CREATE The Footer
INT bodyfontheight =
Bodyfont.getHeight (ev.graphics);
Rectanglef Footer = New
Rectanglef (Left Margin, Body.Bottom,
PageWidth, Bodyfontheight;
// Create The Body Section
Rectanglef body = new
Rectanglef (LeftMargin, Header.bottom,
PageWidth, PageHeight -
Bodyfontheight);
Listing 5 C #
PRINTPAGE Provides the key to printing.
The PrintPage event is the primary event you'll use when printing using the System.Drawing.Printing objects. This event fires once per page until you set the value of ev.HasMorePages to false. The code used to retrieve the hard margins makes up For Any Shortcomings in The .NET Framework.
Private Void Doc_PrintPage (Object Sender,
System.drawing.printing.printpageeventargs ev) {
_CurrentPage ;
String headertext = "Northwinds Customer Contacts";
INTPTR HDC = ev.Graphics.getHDC ();
ev.Graphics.ReleaseHDC (HDC);
Marginfo mi = new marginfo (hdc.toint32 ()); // Take The Hard Margins Into Account ...
Float leftmargin = ev. Marginbounds.Left - mi.Left;
Float Right Margin = ev. marginbounds.right;
FLOAT TOPMARGIN = ev. Marginbounds.top - mi.Left;
Float bottommargin = ev. marginbounds.bottom
Float Pageheight = BOTTOMMARGIN - TOPMARGIN
Float PageWidth = Right Margin - LeftMargin;
Float headerheight =
Headerfont.getHeight (ev.graphics);
Float footerheight = bodyfont.getHeight (ev.graphics);
// Report Header
Rectanglef Reportheaderr = New Rectanglef (Left Margin,
TopMargin, PageWidth, HeaderHeight;
// Report Body
Rectanglef BodyR = New Rectanglef (Leftmargin,
Reportheaderr.bottom, PageWidth, PageHeight -
Reportheaderr.Height - FooterHeight;
// Report Footer
Rectanglef Reportfooterr = New Rectanglef (LeftMargin,
Bodyr.Bottom, PageWidth, FooterHeight * 2);
// Results of using the split function on the text
String [] EL;
// a line of text from Our file
String text = "";
// Print The Header ONCE PER PAGE
Centertext (ev.graphics, headertext, headerfont,
Defaultbrush, ReportHeaderr;
// the header is equal to 2 Normal Lines
INT Currentline = 2;
// How Many Lines Can We Fit on a page?
INT linesPERPAGE = Convert.Toint32 (Bodyr.Height /
Bodyfont.getHeight (ev.graphics)) - 1;
Float Bodyfontheight =
Bodyfont.getHeight (ev.graphics);
Float currenty;
// Print Each line of the file.
While (Currentline ((text = data.readline ())! = NULL)) { EL = text.split (','); Currenty = GetCurrenty (Currentline, Topmargin, Bodyfontheight); Ev.graphics.drawstring (EL [0], BodyFont, Defaultbrush, Bodyr.Left, Currenty; Currentline ; currenty = getCurrenty (Currentline, Topmargin, Bodyfontheight); Ev.graphics.drawstring (el [1], Bodyfont, Defaultbrush, Bodyr.Left 20, Currenty); Currentline ; Currenty = GetCurrenty (Currentline, Topmargin, Bodyfontheight); Ev.graphics.drawstring ("Phone:" EL [2], Bodyfont, Defaultbrush, Bodyr.Left 20, Currenty); Currentline ; Currenty = GetCurrenty (Currentline, Topmargin, Bodyfontheight); Ev.graphics.drawstring ("Fax:" EL [3], Bodyfont, Defaultbrush, Bodyr.Left 20, Currenty); Currentline ; Currenty = GetCurrenty (Currentline, Topmargin, Bodyfontheight); Ev.graphics.drawline (Pens.Black, Left Margin, Currenty, ev. marginbounds.right, currenty; } // Page Number CenterText (ev.graphics, "page" CurrentPage.toString (), BodyFont, DEFAULTBRUSH, Reportfooterr); IF (Text! = null) { ev.hasmorepages = true; } else { // no more pages to print ev.hasmorepages = false; } } Private float getcurrenty (int currentline, float TopMargin, Float Fontheight) { Return TopMargin (Currentline * fontheight); } Private Void Centertext (Graphics G, String T, Font F, Brush B, Rectanglef Rect) { StringFormat sf = new stringFormat (); sf.alignment = StringAlignment.center; g.drawstring (T, F, B, RECT, SF); } Complete source code: using system; using system.drawing; using system.drawing.printing; using system.componentmodel; using system.windows.form; Namespace PrintTest {Public Class Printform: System.Windows.Forms.form { // private variables private PrintDocument _PDoc; private StreamReader _Data; private int _currentPage = 0; // these will be created in BeginPrint and // destroyed in EndPrint private Font _headerFont;. Private Font _bodyFont; private Brush _defaultBrush = Brushes.Black; private Pen _defaultPen = new Pen (Brushes.Black, .25f); private System.Windows.Forms.Button PreviewButton; private System.Windows.Forms.Button PrintButton; private System.Windows.Forms.Label StatusLabel; /// Public printform () {initializationComponent (); Protected Override Void Dispose (bool disposing) {if (disponents! = null) {components.dispose ();}} Base.Dispose (Disposing); #region Windows Form Designer generated code /// /////Printformasesize = new system.drawing.size (5, 13); this.clientsize = new system.drawing.size (370, 71); this.Controls.Addrange (New System.Windows. Forms.Control [] {this.StatusLabel, this.PrintButton, this.PreviewButton}); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; this.MaximizeBox = false; this.Name = "PrintForm"; this. Text = "Print Demo"; this.Load = New System.EventHandler (this.printform_load); this.ResumeLayout (false);} #ENDREGION [Stathread] static void main () {Application.run (new printform ()); Private Void PreviewButton_Click (Object Sender, System.EventArgs E) {PrintPreviewDialog PreviewDialog = New PrintPreViewDialog (); // display a pagesetup dialog PageSetupDialog pageSetup = new PageSetupDialog (); pageSetup.Document = _PDoc; DialogResult Rc = pageSetup.ShowDialog (); if (Rc == DialogResult.Cancel) {return;} // display the preview dialog previewDialog.Document = _PDoc; previewDialog.PrintPreviewControl.Zoom = 1.0; previewDialog.WindowState = FormWindowState.Maximized; previewDialog.ShowInTaskbar = true; previewDialog.ShowDialog ();} Private void _pdoc_printpage (Object sender, system.drawing.printing.printpageeventargs ev) {_CurrentPage ; String headertext = "Northwinds Customer Contacts"; Marginfo mi; FLOAT Right Margin = 0f; float topmargin = 0f; float bottommargin = 0f; float pageWidth = 0f; float pagewidth = 0f; // Retrieve The Hard Printer Margins INTPTR HDC = ev.Graphics.GethDC (); try {mi = new marginfo (hdc.toint32 ());} finally {ev.graphics.releaseHDC (HDC);} ev.graphics.pageUnit = GraphicsUnit.inch; ev.graphics.pagescale = .01f; ev.graphics.translateTransform (-mi.left, -mi.top); // retrieve the margins leftMargin = ev.MarginBounds.Left - mi.Left; rightMargin = ev.MarginBounds.Right; topMargin = ev.MarginBounds.Top - mi.Top; bottomMargin = ev.MarginBounds.Bottom; pageHeight = bottomMargin - topMargin PageWidth = Right Margin - Leftmargin; // used to define the sections of the document float headerHeight = _Headerfont.getHeight (ev.graphics); float footerheight = _BodyFont.getHeight (ev.graphics); // report header RectangleF ReportheaderR = new RectangleF (leftMargin, topMargin, pageWidth, headerHeight); // report body RectangleF bodyR = new RectangleF (leftMargin, ReportheaderR.Bottom, pageWidth, pageHeight - ReportheaderR.Height - footerHeight); // report footer RectangleF ReportfooterR = new RectangleF (leftMargin, bodyR.Bottom, pageWidth, footerHeight * 2); // uncomment these lines to draw borders around the rectangles / * drawRect (ev.Graphics, _defaultPen, leftMargin, topMargin, pageWidth, headerHeight); drawRect (ev.Graphics, _defaultPen, leftMargin, ReportheaderR.Bottom, pageWidth, pageHeight - ReportheaderR.Height - footerHeight); drawRect (ev.Graphics, _defaultPen, leftMargin, bodyR.Bottom, pageWidth, ReportfooterR.Height); centerText (ev.Graphics , "Header section", _headerfont, _defaultbrush, reportheaderr); CE NTERText (Ev.graphics, "Body Section", _Headerfont, _defaultbrush, bodyr); CenterText (ev.graphics, "footer section", _headerfont, _defaultbrush, reportfooterr); return; * / // Results of using the split function on the text string [] data; // a line of text from out from ou file string text = "" // Print The Header Once Per page centertext (ev.graphics, headertext, _headerfont, _defaultbrush, reportheaderr); / h m = = = = on = = = = =;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; // the header = 2 lines int currentline = 2; // currenty is what we'll Use for the top (y) Coordinate That // DrawString Needs. float currenty = 0; // Print Each Line of the File. this Could Be Easily Modified to // DEAL WITH DATA from A DataTable While (Currentline 1 // retrieve the current top position currentY = getCurrentY (currentLine , bodyR.Top, bodyFontHeight); // DrawString will take a Rectangle argument, but NOT a RectangleF arg, // so we need to provide the X and Y arguments ev.. Graphics.DrawString (data [0], _bodyFont, _defaultBrush, bodyR.Left, currentY); currentY = getCurrentY (currentLine , bodyR.Top, bodyFontHeight); ev.Graphics.DrawString (data [1], _bodyFont, _defaultBrush, bodyR. Left 25, currentY); currentY = getCurrentY (currentLine , bodyR.Top, bodyFontHeight); ev.Graphics.DrawString ( "Phone:" data [2], _bodyFont, _defaultBrush, bodyR.Left 25, currentY); currentY = getCurrentY (currentLine , bodyR.Top, bodyFontHeight); ev.Graphics.DrawString ( "Fax:" data [3], _bodyFont, _defaultBrush, bodyR.Left 25, currentY); // currentY = getCurrentY (currentLine , TopMargin, bodyFontHeight); //ev.Graphics.DrawLine(_defaultPen, leftMargin, currentY, pageWidth, currentY); currentLine ;} // page number centerText (ev.Graphics, "Page" _currentPage.ToString (), _bodyFont _Defaultbrush, reportfooterr; // do we have more pages to print? If (text! = Null) {ev.hasmorepages = true;} else {ev.haASMOREPAGES = false;}} private float getCurrentY (int currentLine, float topMargin, float fontHeight) {return topMargin (currentLine * fontHeight);} // my wrapper for DrawRectangle private void drawRect (Graphics g, Pen p, float left, float top, float width, float Height) {g.drawRectangle (_Defaultpen, left, top, width, height);} // the StringFormat class has a lot of cool features private void centerText (Graphics g, string t, Font f, Brush b, RectangleF rect) {StringFormat sf = new StringFormat (); // center horizontally sf.Alignment = StringAlignment.Center ; // center vertical = stringAlignment.center; g.drawstring (t, f, b, reCT, sf);} // use for debugging private void dumpRectf (Rectanglef Rect) {system.diagnostics.debug.writeline ());} Private void _pdoc_beginprint (Object Sender, Printeventargs PV) {// Make Sure We Reset this Before Printing_CurrentPage = 0; // the file should be in the same folder as the EXE _Data = new StreamReader ( "contacts.csv"); _headerFont = new Font ( "Arial", 24, FontStyle.Underline, GraphicsUnit.World); _bodyFont = new Font ( "Arial", 12, graphicsUnit.world; Private void _pdoc_endprint (Object Sender, Printeventargs PV) {_data.close (); _Headerfont.dispose (); _bodyfont.dispose (); Private void _pdoc_querypagesettings (ibject sender, querypagesettingseventargs ev) {} private void PrintForm_Load (object sender, System.EventArgs e) {_PDoc = new PrintDocument (); // this is what will show up in the print manager _PDoc.DocumentName = "printTest - Northwind Contact List"; // make sure at least one printer is installed if (_PDoc.PrinterSettings.PrinterName == " IF (rc == DialogResult.ok) {_pdoc.print ();}}}}