I have a VB.NET program that uses PDF Sharp to dump information to a PDF file. The problem i'm having is I can't figure out how to jump to the next page if ypoint
(length of the page) is at a certain value. Indicated by ** before the if ** at the end if. Below is a section of my pdf sharp dump. I thought I could use an if then statement to increase a counter and add the variable to the end of the pdfpage... for example
pdfpage(ypointcounter)....
This doesn't work. You'll see I tried separating the top portion (my heading), because I don't want to repeat that on the next page, and is not part of my loop through to dump the info from multiple datasets. I know I can insert a new page, and I also know how to write to the second page. What i'd like to do is setup the program, inside my loop, to automatically create the next page, and begin writing to it if i'm at the end of a page. I assume I have to setup some sort of array?
Any Help?
My code is:
Try
yPoint = 0
Dim pdf As PdfDocument = New PdfDocument
pdf.Info.Title = "Last Hour Comparison"
Dim pdfPage As PdfPage = pdf.AddPage
Dim pdfPage1 As PdfPage = pdf.AddPage
Dim graph As XGraphics = XGraphics.FromPdfPage(pdfPage1)
Dim fontheader As XFont = New XFont("Arial", 12, XFontStyle.Bold) ' I used this as a header. Basically-
'Just made the font bigger and style is BOLD
Dim font As XFont = New XFont("Arial", 11, XFontStyle.Regular)
'This sets the Header----------------------------------------------------------------------------
graph.DrawString("Test Last Hour Comparison for week of " & Weekstart, fontheader, XBrushes.Black, _
New XRect(20, yPoint, pdfPage.Width.Point, pdfPage.Height.Point), XStringFormats.TopLeft)
yPoint = yPoint + 40
'---------------------------------
'This is for building the Report ---------------------------------------------------------
'If ds.Tables(0).Rows.Count > 0 Then
graph.DrawString("Location", font, XBrushes.Black, _
New XRect(20, yPoint, pdfPage.Width.Point, pdfPage.Height.Point), XStringFormats.TopLeft)
graph.DrawString("Date", font, XBrushes.Black, _
New XRect(120, yPoint, pdfPage.Width.Point, pdfPage.Height.Point), XStringFormats.TopLeft)
graph.DrawString("# 6-7 Visits ", font, XBrushes.Black, _
New XRect(280, yPoint, pdfPage.Width.Point, pdfPage.Height.Point), XStringFormats.TopLeft)
graph.DrawString("# 7-8 Visits ", font, XBrushes.Black, _
New XRect(340, yPoint, pdfPage.Width.Point, pdfPage.Height.Point), XStringFormats.TopLeft)
graph.DrawString("% Change ", font, XBrushes.Black, _
New XRect(410, yPoint, pdfPage.Width.Point, pdfPage.Height.Point), XStringFormats.TopLeft)
Dim x As Integer
x = 0
LocationCounter = 1
ypointcounter = 0
**For i = 0 To 3
GetLocation()
yPoint = yPoint + 20
If yPoint > 840 Then
yPoint = 20
ypointcounter = ypointcounter + 1
End If**
graph.DrawString(LocationName, font, XBrushes.Black, _
New XRect(20, yPoint, pdfPage(ypointcounter).Width.Point, pdfPage(ypointcounter).Height.Point), XStringFormats.TopLeft)
dtstartdate = Today.AddDays(-6)
firsthourweektotal = 0
secondhourweektotal = 0
For z = 0 To 6
firsthour = ds.Tables(0).Rows(x).Item(0)
secondhour = ds2.Tables(0).Rows(x).Item(0)
firsthourweektotal = firsthourweektotal + ds.Tables(0).Rows(x).Item(0)
secondhourweektotal = secondhourweektotal + ds2.Tables(0).Rows(x).Item(0)
If ds.Tables(0).Rows(x).Item(0) = 0 Then
Percentage = 0
Else
Percentage = Math.Round(ds2.Tables(0).Rows(x).Item(0) / ds.Tables(0).Rows(x).Item(0) * 100, 2)
End If
graph.DrawString(dtstartdate.DayOfWeek.ToString & ", " & dtstartdate.Month & "/" & dtstartdate.Day, font, XBrushes.Black, _
New XRect(110, yPoint, pdfPage(ypointcounter).Width.Point, pdfPage(ypointcounter).Height.Point), XStringFormats.TopLeft)
graph.DrawString(firsthour, font, XBrushes.Black, _
New XRect(288, yPoint, pdfPage(ypointcounter).Width.Point, pdfPage(ypointcounter).Height.Point), XStringFormats.TopLeft)
graph.DrawString(secondhour, font, XBrushes.Black, _
New XRect(352, yPoint, pdfPage(ypointcounter).Width.Point, pdfPage(ypointcounter).Height.Point), XStringFormats.TopLeft)
graph.DrawString(Percentage, font, XBrushes.Black, _
New XRect(418, yPoint, pdfPage(ypointcounter).Width.Point, pdfPage(ypointcounter).Height.Point), XStringFormats.TopLeft)
dtstartdate = dtstartdate.AddDays(1)
yPoint = yPoint + 20
x = x + 1
Next
You have sort of boxed yourself in with the idea of the arrays. It sounds like what you really want is a way to start a new page and redraw the header on the fly when YPosition gets to a certain point. Note: With such questions we are guessing at the result, format, layout and grouping based on what it looks like the code is doing. For example, it is not entirely clear if the report is grouped by location or date. That should not matter since the concept is the same.
To do this, I wrote a class of primitives to manage printing in a loop, creating a new page when desired. My test data was a Dictionary(Of String, List(of VisitInfo))
, but as I said, I think I got that inside out (based on "comparison" in the header). I also cleaned up the code to Dispose
of resources, such as XGraphics
objects which are leaking in yours.
Public Class PDFReport
Private filePath As String
Private pdf As PdfDocument ' this also needs to be disposed of
Private hFont As XFont
Private tFont As XFont
' the current page, current Y
Private pdfPage As PdfPage
Private CurrentY As Integer
Public Sub New(fPath As String)
filePath = fPath
pdf = New PdfDocument()
pdf.Info.Title = "Last Hour Comparison"
hFont = New XFont("Arial", 14, XFontStyle.Bold)
tFont = New XFont("Arial", 11, XFontStyle.Regular)
End Sub
' this is specialized to print the dictionary of data
Public Sub WriteDoc(col As Dictionary(Of String, List(Of Visit)))
' skip page ?? in OP
pdf.AddPage()
Dim vl As List(Of Visit)
' the string key is the location name
For Each kvp As KeyValuePair(Of String, List(Of Visit)) In col
vl = kvp.Value
' this always starts a new page when the location
' changes even if there is room.
' otherwise, you could just call DrawHeader
StartNewPage(vl(0).Location, vl(0).VDate.ToShortDateString)
For Each v As Visit In vl
If CurrentY >= 780 Then
StartNewPage(v.Location, v.VDate.ToShortDateString)
End If
PrintLine(v)
Next
Next
pdf.Save(filePath)
pdf.Dispose() ' dispose of resource
End Sub
' prints one line of data, increments Y
Private Sub PrintLine(v As Visit)
Using g As XGraphics = XGraphics.FromPdfPage(pdfPage)
g.DrawString(String.Format("{0}, {1}/{2}",
v.VDate.DayOfWeek.ToString,
v.VDate.Month, v.VDate.Day),
tFont, XBrushes.Black,
New XRect(110, CurrentY, pdfPage.Width.Point,
pdfPage.Height.Point),
XStringFormats.TopLeft)
g.DrawString(v.Foo.ToString, tFont, XBrushes.Black,
New XRect(288, CurrentY, pdfPage.Width.Point, pdfPage.Height.Point),
XStringFormats.TopLeft)
g.DrawString(v.Bar.ToString, tFont, XBrushes.Black,
New XRect(352, CurrentY, pdfPage.Width.Point, pdfPage.Height.Point),
XStringFormats.TopLeft)
CurrentY += 20
End Using ' dispose of XGraphic object
End Sub
' called when a new page is needed
' updates the pdf object var, Resets CurrentY to top of page
' and draws the header
Private Sub StartNewPage(loc As String, dt As String)
pdfPage = pdf.AddPage()
CurrentY = 20
DrawHeader(loc, dt)
End Sub
Private Sub DrawHeader(loc As String, WeekStart As String)
Using g As XGraphics = XGraphics.FromPdfPage(pdfPage)
g.DrawString("Test Last Hour Comparison for week of " & WeekStart, hFont,
XBrushes.Black,
New XRect(20, CurrentY, pdfPage.Width.Point,
pdfPage.Height.Point),
XStringFormats.TopLeft)
CurrentY += 40
g.DrawString(loc, tFont, XBrushes.Black,
New XRect(20, CurrentY, pdfPage.Width.Point,
pdfPage.Height.Point),
XStringFormats.TopLeft)
g.DrawString("Date", tFont, XBrushes.Black,
New XRect(120, CurrentY, pdfPage.Width.Point,
pdfPage.Height.Point),
XStringFormats.TopLeft)
g.DrawString("# 6-7 Visits ", tFont, XBrushes.Black,
New XRect(280, CurrentY, pdfPage.Width.Point,
pdfPage.Height.Point),
XStringFormats.TopLeft)
g.DrawString("# 7-8 Visits ", tFont, XBrushes.Black,
New XRect(340, CurrentY, pdfPage.Width.Point,
pdfPage.Height.Point),
XStringFormats.TopLeft)
g.DrawString("% Change ", tFont, XBrushes.Black, _
New XRect(410, CurrentY, pdfPage.Width.Point,
pdfPage.Height.Point),
XStringFormats.TopLeft)
End Using ' dispose of XGraphic object
CurrentY += 20
End Sub
End Class
In a nutshell, drawing the header/caption is encapsulated in one procedure, starting a new page in another and printing a line of data in another. WriteDoc
, which is just a control procedure, loops thru the data simply feeding the current data point (a List item in mine, a ds item in yours) to PrintLine
. That control procedure itself wont do you much good. It exists mainly to show how to orchestrate calls to the local methods described to get the result.
When it sees CurrentY
is beyond a certain point, it pauses from feeding lines to call StartNewPage
, then continues. The test data does not matter, but calling it from a button click is simple:
Dim pdf As New PDFReport("C:\Temp\Visits.pdf")
pdf.WriteDoc(col) ' col is my dictionary of fake data
Output/page break in flow:
Works on My MachineTM