About System.Drawing.print Namespace Management and Implementation
1. Two work to do when we print:
1. Draw the text to be printed:
The drawing work is made in the process of processing of the PrintDocument's PrintPage event. In this event, the PrintPageEventArgs parameters give us the relevant information of the necessary Graphics objects and printing leaves.
First, we have to know the size of the area that can be used. In the PrintPageEventArgs, such information is stored in MarginBounds. This way we can calculate the number of rows and columns we can draw on a page.
Int linesPage = marginbounds.height / lineheight;
INT colsperpage = marginbounds.width / colwidth;
This way we can use these parameters in the printed loop to determine when a page print is completed.
INT linecount = 0;
INT colcount = 0;
While (Linecount { // Line Drawing Codes While (Colcount { // Column Drawing Codes ... COLCOUNT ; } ... Linecount ; } This way, we can easily print out the contents of the page. After the print is finished, if there is more pages that need to be printed, just set printpageeeventargs.hasmorepages to TURE. When the last page is completed, set this property to false to abort printing. 2. Call print The drawing of the page is the biggest part of our best to do. The rest of us can declare some objects, and call some functions can be completed. First, we declare a PrintDocument object. Such as: PRINTDocument Document = New PrintDocument (); Then, the print event handler we have completed is then connected to this object. Such as: Document.printpage = new printpageeventhandler (myprintpage); In this way, the preparation of prints is done. Now just call the printDocument's print () method in the place where you want to start printing. Document.print (); If you want to have a printed preview, you can write this in your print preview button: PRINTPREVIEWDIALOG prevdlg = new printpreviewDialog (); prevdlg.document = document; prevdlg.showdialog (); In this way, the work related to print is done. Second, the internal implementation of simple work: Above, we know how to implement your own print function in C #. So how do these doing this in DOTNET? How is this process controlled? Now let's talk about this. 1. Related classes: a) PRINTPAGEEVENTHANDLER; b) PRINTPAGEEVENTARGS; c) printdocument; d) PrintControl; e) StandardPrintController; (PrintController subclass) f) previewPrintController; (subclass of PrintController) g) querypagesettingseventargs 2. Logic implementation: When we instantiate a PrintDocument object, PrintDocument's constructive function creates a printsettings object, and then set your own PrintController object empty, and finally use the PrintSettings object to create a default page settings. When we call the PrintDocument's Print method, call the print method of the PrintController object. In the GET method for the PrintDocument object's PrintController property, a StandardpringController object will be created when this object is empty. The PRINTDocument object is called to be such a PrintController object. (Different from this in the printing preview. When the PrintDocument object is passed to the PrintPreviewDialog object, there will be a PreviewPrintController object to be set to the PrintDocument object.) The StandardPrintController object and the Difference of the PreviewPrintController object are different in the creation of the Graphics object. The StandardPrintController object creates a Graphics object using the printer device DC. The PreviewPrintController object uses Metafile (iMage) to create a Graphics object. In the PrintController's Print method, you first call your own onStartPrint method to set the print mode. (Initialization using defaultpagesetting in the PrintDocument object.) Then call the printloop method to control each page. The PrintLoop method controls this printing cycle, which is also the source we can receive a PrintPage event when printing at each page. The first job in PrintLoop is to create a PrintPageEventArgs object and create a Graphics object. The creation of this Graphics object is to call his subclass Override's onStartPage method. So, our page draws what kind of HDC will depend on what kind of PrintController used. Then, this Graphics object is placed in the PrintPageEventArgs object. Call OnPrintPage commission. That is, our drawing function. After that, call OneEndPage to complete the print of a page. This completes a page drawing. For multi-page printing, it is controlled using a do-whilele. This loop is controlled by two signs. One is whether the user cancels the printing; the other is the status of the HasMorePages property. Detailed control See the function code of the third part. 3. Third, the code implementation of some key functions: 1. PRINTDocument: Public Class PrintDocument: System.comPonentModel.component { Public PrintDocument () { THIS.DocumentName = "Document"; This.printersettings = new printersettings (); This.printController = NULL; this.defaultpagesettings = NEW PageSettings (this.printersettings); } Public void print () { PrintController Controller; controller = this.printController; Controller.print (this); } Protected Virtual Void OnBeginPrint (Printeventargs E) { IF (this.beginprinthandler! = null) This.beginprintHandler.Invoke (this, e); } } 2. PrintController: Public Class PrintController: System.Object { Public PrintController () { THIS.ModeHandle = INTPTR.ZERO; INTSecurity.sageprinting.Demand (); } Internal void print (PrintDocument Document) { Printeventargs args; Bool flag; INTSecurity.safeprint.demand (); Args = new printeventargs (); Document._onbeginprint (args); IF (args.cancel) Return; THIS.OnStartPrint (Document, Args); Flag = true; Try { Flag = this.printloop (document); } Finally { Try { Document._onenndprint (args); Args.cancel = (flag | args.cancel); Return; } Finally { This.onEndPrint (Document, Args); } } } Public void OnStartPrint (PrintDocument Document, Printeventargs E) { Intsecurity.allprintingandunmanagedcode.assert (); this.modehandle = Document.printersettings.GethDevmode Document.defaultpagesettings; } Private Bool PrintLoop (PrintDocument Document) { QueryPagesettingSeventargs settingargs; PRINTPAGEEVENTARGS Eventargs; Graphics graphics; Settingargs = new querypagesettingseventargs (Pagesettings) Document.defaultPageSettings.clone ()); DO { Document._onquerypagesettings (settingargs); IF (settingargs.cancel) Return True; Eventargs = this.createprintpageEvent (Settingargs.pagesetting); Graphics = this.onstartPage (Document, EventArgs); Eventargs.SETGRAPHICS (Graphics); Try { Document._openprintpage (evenetargs); This.onEndPage (Document, Eventargs); } Finally { Eventargs.dispose (); } } while (! Eventargs.cancel && evenetargs.hasmorepages); } 3. StandardPrintController: Public Class StandardPrintController: PrintController { Public Void OnStartPage (PrintDocument Document, PrintPageEventArgs E) { INTPTR PTR1; INTPTR PTR2; Int Num1; Int Num2; Int Num3; Int Num4; FLOAT SINGLE1; FLOAT SINGLE2; Int Num5; Rectangle Rectangle1; this.checksecurity (document); Base.onstartPage (Document, E); Intsecurity.allprintingandunmanagedcode.assert (); E.PageSettings.copyToHDEVMODE (BASE.ModeHandle); Ptr1 = SafenativeMethods.globalock ( New Handleref (this, base.modehandle); Try { Ptr2 = SafenativeMethods.Resetdc ( New Handleref (this, this.dc), New Handleref (NULL, PTR1)); IF (Ptr2 == INTPTR.ZERO) { Throw new win32exception (); } } Finally { SafenativeMethods.globalunlock New Handleref (this, base.modehandle); } THIS.GRAPHICS = graphics.fromhdcinternal (this.dc); IF ((this.graphics! = null) && document.originatmargins) { Num1 = unsafenativeMethods.getDeviceCaps ( New HandleRef (Null, this.dc), 88); Num2 = unsafenativeMethods.getDeviceCaps ( New Handleref (Null, this.dc), 90); Num3 = unsafenativeMethods.getDeviceCaps ( New Handleref (NULL, THIS.DC), 112); Num4 = unsafenativeMethods.getDeviceCaps ( New Handleref (NULL, THIS.DC), 113); SINGLE1 = ((Float) ((Num3 * 100) / Num1)); SINGLE2 = ((FLOAT) ((NUM4 * 100) / Num2); THIS.GRAPHICS.TRANSLATTRANSFORM (-SINGLE1, -SINGLE2); Rectangle1 = E.Marginbounds; Rectangle1 = E.Marginbounds; this.graphics.translateTransform (float) Rectangle1.x, (float) Rectangle1.y); } Num5 = SafenativeMethods.StartPage ( New Handleref (this, this.dc)); IF (NUM5 <= 0) { Throw new win32exception (); } Return THIS.GRAPHICS; } } 4. PreviewPrintController: PUBLIC CLASS Preview Class PreviewPrintController: PrintController { Public Override Graphics OnStartPage (PrintDocument Document, PrintPageEventArgs E) { Size size1; Size size2; MetaFile Metafile1; PreviewPageInfo Info1; Rectangle Rectangle1; THIS.CHECKSECURITY (); Base.onstartPage (Document, E); Intsecurity.allprintingandunmanagedcode.assert (); E.PageSettings.copyToHDEVMODE (BASE.ModeHandle); Rectangle1 = E.PageBounds; Size1 = Rectangle1.size; Size2 = printerUnitconvert.convert (Size1, 0, 2); Metafile1 = New Metafile THIS.DC, New Rectangle (0, 0, Size2.Width, Size2.Height); Info1 = new previewPageInfo (Metafile1, Size1); THISLIST.ADD (Info1); this.graphics = graphics.fromimage (metafile1); IF (this.ntialias) { THIS.GRAPHINT = 4; THIS.GRAPHICS.SMOOTHINGMODE = 4; } Return THIS.GRAPHICS; } } Fourth, summary: The basic control logic of printing in .NET is like this. Of course, this is just my rough sorting. There may be a lot of details that have not been analyzed. In addition, regarding how the WM_PAINT message in Windows works with these controls, there is no way to understand from the code we can see. After all, the real underlying thing in .NET is still developed using C / C . So these aspects are not easy to get. If a high person has this information, I hope to provide it. While everyone can better understand some .NET mechanisms. Learn more things!