Printing with PrintDocument in .Net

Pieter van der Westhuizen, a professional freelance web & mobile developer and founder of Coalition Software.
Search for a command to run...

Pieter van der Westhuizen, a professional freelance web & mobile developer and founder of Coalition Software.
A recent requirement came up for configurable dynamic forms in a mobile application. There are a few dynamic form packages for Flutter, but I wanted a bit more control over the schema and behavior of the form. Here follows my attempt at creating dyna...

If you've ever written a mobile app with Flutter that integrates with an API, then you'll know that there are a lot of model objects that get passed between the app and the API. JSON Serialization in Flutter can also take a fair amount of boilerplate...

Back in May 2020, Microsoft announced a new feature for Azure Blob Storage called Blob Index. Essentially, this enables you to add key/value tags to your Blob objects and be able to query said Blob objects without having to use a separate service lik...

In my last post, "Using AWS Cognito with Xamarin Forms", I showed how to authenticate with Amazon Cognito using Xamarin Forms and the Xamarin.Essentials Web Authenticator. In this post, we'll go through the process of using the AWS Cognito Hosted UI ...

In this post, I'll show you how to quickly and easily set up user authentication for your Xamarin Forms app using Amazon Cognito. AWS Cognito is a user identity management solution by Amazon. It is a really easy way to add authentication to your appl...

In recently needed to print labels/tickets on a series of ZEBRA printers.

This required some very specific sized labels/tickets. At first I designed everything in Crystal Reports, and everything previewed perfectly,until… I actually had to print it to the printer. The printer driver plays a very specific role, and can cause some serious headaches.
Eventually I resorted to using the .Net PrintDocument component, that allows you to specify the paper size and print to the printer on a lower level than Crystal Reports. This worked very nicely for one label/ticket, but I wanted to print a range of labels/tickets.
The Printdocument has a very strange way of processing the print command. In it’s PrintPage event, you set the e.HasMorePages property if you want to print more than one page, and the PrintPage method loops until e.HasMorePages is false. Talk about a messing with your train of thought.
What I needed was a way to say to the PrintDocument that it should print the next page, and then pass my ticket object with the next ticket’s information. Easier said than done. Fortunately, I stumbled onto this forum discussion. This code creates a custom class that inherits from the PrintDocument and give you a nifty .NextPage sub. This let’s the PrintDocument know that you’re moving onto the next page. I’m reposting it here for your convenience.
Printers sure are a lot of fun to try and figure out…depends on your opinion of fun 
Class code:
Imports System.Threading
Imports System.Drawing.Printing
Public Class PrintDoc
Inherits PrintDocument
Private W1, W2 As EventWaitHandle
Private PagesPrinted As Int32
Public Event PrintPages(ByVal Sender As Object, ByRef e As System.Drawing.Printing.PrintPageEventArgs)
Private T As Thread
Private eRef As System.Drawing.Printing.PrintPageEventArgs
Protected Overrides Sub OnPrintPage(ByVal e As System.Drawing.Printing.PrintPageEventArgs)
eRef = e
If PagesPrinted = 0 Then T.Start() Else W2.Set()
PagesPrinted += 1
W1.WaitOne()
End Sub
Private Sub PrintDoc\_BeginPrint(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintEventArgs) Handles Me.BeginPrint
W1 = New EventWaitHandle(False, EventResetMode.AutoReset)
W2 = New EventWaitHandle(False, EventResetMode.AutoReset)
T = New Thread(AddressOf RaisePrintPages)
PagesPrinted = 0
End Sub
Public Sub NextPage()
eRef.HasMorePages = True
W1.Set() : W2.WaitOne()
End Sub
Private Sub RaisePrintPages()
RaiseEvent PrintPages(Me, eRef)
W1.Set()
End Sub
Private Sub PrintDoc\_EndPrint(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintEventArgs) Handles Me.EndPrint
W1.Close() : W2.Close()
End Sub
End Class
Code Implementation:
Private Sub PrintDoc1_PrintPages(ByVal Sender As Object, ByRef e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDoc1.PrintPages
e.Graphics.DrawString("Hello", New Font("Arial", 12, FontStyle.Regular), Brushes.Black, 100, 100)
PrintDoc1.NextPage()
e.Graphics.DrawString("Hello Again", New Font("Arial", 12, FontStyle.Regular), Brushes.Black, 100, 100)
End Sub