PrintDocument and HasMorePages issue

K

kig25

Hello,

When using the VB.NET PrintDocument class, I seem to be encountering an
issue where the sub pd_PrintPage handles PrintDocument.PrintPage (upon
continuing if HasMorePages = true) will paint the next page on top of
the original page. In a sample data case where the source is long
enough to fill three pages, I end up with four calls to pd_PrintPage
which render onto two printed sheets. Historical posts in this forum
from 2003 and 2005 suggested several tactics:

1) Explicitly call Exit Sub after setting HasMorePages = true
2) Defining the PrintDocument object in code instead of with the visual
component
3) Avoiding the Addhandler statement before calling pd.Print():
AddHandler pd.PrintPage, AddressOf Me.pd_PrintPage

In my current code, I have implemented # 1 and 2. I was unable to get
any output under #3. Are there any further tactics to try?

I remain suspicious of the AddHandler, though I haven't been able to
work around it yet -- could I have two concurrent pd_PrintPage threads,
rendering to the same target? It seems unlikely, because my page
counter is incremented between these calls.

I thought I had this resolved yesterday with this code as-is, but as it
happens, it worked successfully to print 3 distinct pages under only
one case: where I had put in debugging break at the start of
pd_PrintPage and stepped through all steps.

Even if I put in a few breaks, but "F5" to accelerate between them, the
issue continues to occur. Nevertheless, I've been trying to identify
the specific step (maybe I should introduce an artifical delay? In the
print event model, is there a way to force the pd_PrintPage execution
to wait for, ie, synchronous feedback from the printer before
continuing to render the next page if I suspect the local network to
the printer is slow?)

I once suspected I was sloppy about margins (and have attempted in code
to be somewhat cleaner), and that I may have pixels rendering outside
the printable bounds of the page, but I don't think this would cause
the PrintPage re-iteration to stay on the same sheet. Also, because
the app worked on debug mode with the same data and graphic element
positioning, I no longer suspect this angle. Is this something to
pursue?

Here is the code I'm working with. There is a button click event
handler, a beginPrint which initializes PrintPageCount as a page
counter, and the PrintPage sub, which uses the page counter to
determine which elements from an array of my own user controls
(ComponentCollection) to render on the page. This also drives my
HasMorePages = T/F logic. PrintALabel and PrintATextbox are overloaded
methods I wrote that apply the offset parameter to the object's
location, and call appropriate graphics.DrawRectangle and
graphics.DrawString methods.

'****************************************************************
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Try
'Assumes the default printer.
'Dim pd As System.Drawing.Printing.PrintDocument =
PrintDocument1
pd = New System.Drawing.Printing.PrintDocument()

Dim margins As New Printing.Margins(25, 25, 25, 25)
pd.DefaultPageSettings.Margins = margins

AddHandler pd.PrintPage, AddressOf Me.pd_PrintPage
' pd.DefaultPageSettings.Landscape = True
pd.Print()
Catch ex As Exception
MessageBox.Show(ex.Message, "An error occurred while
printing")
End Try
End Sub

'***************************************************************

Private Sub pd_BeginPrint(ByVal sender As Object, ByVal e As
System.Drawing.Printing.PrintEventArgs) Handles pd.BeginPrint
PrintPageCount = 0
FormLocation = Me.ComponentCollection(0).Location
FormLocation.Y = FormLocation.Y -
PrintDocument1.DefaultPageSettings.HardMarginY '- 20
FormLocation.X = PrintDocument1.DefaultPageSettings.HardMarginX
'Me.ScrollControlIntoView(Me.ComponentCollection(0))
End Sub

'***************************************************************

Private Sub pd_PrintPage(ByVal sender As Object, ByVal ev As
System.Drawing.Printing.PrintPageEventArgs) Handles pd.PrintPage
' Draw a picture.
Dim thisFont As New System.Drawing.Font("Microsoft Sans Serif",
8.25!, CType((System.Drawing.FontStyle.Regular),
System.Drawing.FontStyle), System.Drawing.GraphicsUnit.Point, CType(0,
Byte))
Dim thisFormat As New System.Drawing.StringFormat()

'In future, calculate components per page based on size and
paper setting.
Dim ComponentsPerPage As Single = 11

Dim indexStart As Integer = PrintPageCount * ComponentsPerPage
Dim indexEnd As Integer
Dim LastPage As Boolean = False

If Me.ComponentCollection.Length - PrintPageCount *
ComponentsPerPage <= ComponentsPerPage Then
' last page to print
indexEnd = indexStart + Me.ComponentCollection.Length -
PrintPageCount * ComponentsPerPage - 1
LastPage = True
Else
indexEnd = (PrintPageCount + 1) * ComponentsPerPage - 1
'indexStart +
End If
''
Me.ScrollControlIntoView(Me.ComponentCollection(indexStart))

Dim item As SingleComponentControl
Dim i As Integer
' For Each item In Me.ComponentCollection
For i = indexStart To indexEnd
item = Me.ComponentCollection(i)

Dim rePoint As New System.Drawing.Point(FormLocation.X,
item.Location.Y - PrintPageCount * ComponentsPerPage * (item.Height +
5) - FormLocation.Y)
' +5 to height is spacing between components.
item.PrinterCoord = rePoint

ev.Graphics.DrawRectangle(Pens.Gray, item.PrinterCoord.X,
item.PrinterCoord.Y, item.Width - 80, item.Height)
PrintATextbox(item.txtConsumed, item, ev,
Drawing2D.HatchStyle.Percent50)
PrintATextbox(item.txtOnHand, item, ev,
Drawing2D.HatchStyle.Percent05)
PrintATextbox(item.TxtOutstanding, item, ev,
Drawing2D.HatchStyle.Percent75)
Dim lblpt As New Point(5, 36)
PrintALabel(item.Label1, item, ev, lblpt)
Dim shiftleft As New Point(-50, 0)
PrintALabel(item.Label2, item, ev, shiftleft)
' ... etc. Several more labels removed for clarity
PrintALabel(item.Label11, item, ev, shiftleft)
Next i

' iterate page count, footer, and test

PrintPageCount = PrintPageCount + 1

'footer with current page number
ev.Graphics.DrawString("Inventory/Component Report for Job " +
JobNumber.ToString + " -- Page " + PrintPageCount.ToString, thisFont,
Brushes.Black, 40, 950)
' ev.HasMorePages = False

If Not LastPage Then
ev.HasMorePages = True
Exit Sub
Else
ev.HasMorePages = False
End If
End Sub

'***********************************************************
Thank you to anyone for any insight into this issue.

Regards,
Keith Gerritsen
 
K

kgerritsen

I have a solution, but I'm not jazzed by it. I moved the page-count
initialization to the button event, and wrapped a Where around the
pd.Print():


PrintPageCount = 0
Dim LastPage As Boolean = False

While Not LastPage
'try print as separate docs...
'pd.Print()
If Me.ComponentCollection.Length - PrintPageCount *
ComponentsPerPage <= ComponentsPerPage Then
' last page to print
LastPage = True
Else
LastPage = False
End If
pd.Print()
PrintPageCount = PrintPageCount + 1
End While

It still calls the PrintPage twice for each page, but as I don't
increment PrintPageCount in this procedure any more, rendering twice on
each output is of no consequence.

I am managing my page counts and printing each page as a separate
1-page document now. It works, and I'm done with this, but I don't
exactly like it. If I was going to implement a "cancel print" feature,
it would be a pain to accomodate.

Regards,
Keith
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top