i am trying to create a report that loads data from the db: this code:
Public Shared Sub BuildReport(document As PdfDocument, rptID As String)
' Start report content on a new page so the title page remains separate
' Use fixed Letter + 0.5" margins from ReportLayout (do not instantiate DevExpress)
document.Pages.Add()
Dim page As PdfPage = document.Pages(document.Pages.Count - 1)
Dim crop As PdfRectangle = page.CropBox
Dim pageWidth As Double = ModReportLayout.PageWidthPoints
Dim pageHeight As Double = ModReportLayout.PageHeightPoints
Dim marginLeft As Double = ModReportLayout.MarginLeftPoints
Dim marginRight As Double = ModReportLayout.MarginRightPoints
Dim marginTop As Double = ModReportLayout.MarginTopPoints
Dim marginBottom As Double = ModReportLayout.MarginBottomPoints
Dim printableWidth As Double = ModReportLayout.PrintableWidthPoints
Dim centerX As Double = marginLeft + (printableWidth / 2.0)
' baseTop leaves space for overlay header (OverlayHeaderFooterOnFile uses top - 18)
Dim baseTop As Double = crop.Top - marginTop
Dim Y As Func(Of Double, Double) = Function(offset) baseTop - offset
Dim primaryColor As PdfColor = ColorToPdf(ModReportTheme.PrimaryTextColor)
Dim secondaryColor As PdfColor = ColorToPdf(ModReportTheme.SecondaryTextColor)
Dim weekEnding As Date = Date.Now
Try
If FrmWeeklyReports IsNot Nothing Then weekEnding = FrmWeeklyReports.DtpRptDte.Value
Catch
End Try
Dim monday As Date = weekEnding.AddDays(-4)
Dim friday As Date = weekEnding
Dim dateRangeText As String
If monday.Year = friday.Year Then
dateRangeText = monday.ToString("MMM dd") & " - " & friday.ToString("MMM dd, yyyy")
Else
dateRangeText = monday.ToString("MMM dd, yyyy") & " - " & friday.ToString("MMM dd, yyyy")
End If
Dim projectStart As Date = Date.MinValue
Try
projectStart = Date.Parse(ModDefaultProject.RptStartDate)
Catch
projectStart = friday.AddDays(-7)
End Try
Dim daysDiff As Integer = DateDiff(DateInterval.Day, projectStart, friday)
Dim weekNo As Integer = (daysDiff \ 7) + 1
If weekNo < 1 Then weekNo = 1
Dim startOffset As Double = 10.0
' Fonts: normal + header bold (fallbacks)
Dim headerFont As New PdfFont("Tahoma", 10)
Dim headerFontBold As PdfFont = Nothing
Try
headerFontBold = New PdfFont("Tahoma-Bold", 10)
Catch
Try
headerFontBold = New PdfFont("Arial-BoldMT", 10)
Catch
headerFontBold = New PdfFont("Tahoma", 10) ' fallback to regular if bold not available
End Try
End Try
Dim bodyFont As New PdfFont("Tahoma", 10)
' EMPLOYER (top)
Dim ft As New PdfFormattedText() With {.Font = New PdfFont("Tahoma", 12), .Color = ColorToPdf(ModReportTheme.SubtleGray)}
ft.Clear()
ft.Append(If(FrmMain IsNot Nothing, FrmMain.LblDefEmployerName.Text, ""))
page.Content.DrawText(ft, New PdfPoint((pageWidth - ft.Width) / 2.0, Y(0)))
startOffset += 40
' BLUE RULE
ft = New PdfFormattedText() With {.Font = New PdfFont("Tahoma", 6), .Color = primaryColor}
ft.Clear()
ft.Append(New String("─"c, 140))
page.Content.DrawText(ft, New PdfPoint((pageWidth - ft.Width) / 2.0, Y(40)))
startOffset += 40
' TITLE
ft = New PdfFormattedText() With {.Font = New PdfFont("Tahoma", 15), .Color = primaryColor}
ft.Clear()
ft.Append("Weekly Progress Summary")
page.Content.DrawText(ft, New PdfPoint(marginLeft, Y(80)))
' SUBTITLE
Dim c1 As Color = ModReportTheme.PrimaryTextColor
Dim c2 As Color = ModReportTheme.SecondaryTextColor
Dim subtitleX As Double = marginLeft
Dim subtitleY As Double = Y(110)
ft = New PdfFormattedText() With {.Font = New PdfFont("Tahoma", 11), .Color = ColorToPdf(c1)}
ft.Clear()
ft.Append($"({dateRangeText}) ")
page.Content.DrawText(ft, New PdfPoint(subtitleX, subtitleY))
Dim xAfter As Double = subtitleX + ft.Width
ft = New PdfFormattedText() With {.Font = New PdfFont("Tahoma", 10), .Color = ColorToPdf(c2)}
ft.Clear()
ft.Append("Week No. " & weekNo.ToString())
page.Content.DrawText(ft, New PdfPoint(xAfter, subtitleY))
startOffset += 60
' Data: read from DB (use global 'con' connection)
Dim connection As OleDbConnection = con
Dim reader As OleDbDataReader = Nothing
Try
Dim cmd As New OleDbCommand("
SELECT ProgressData, PctCompleted, Status
FROM tblWeeklyReportsProgress
WHERE RptID = @ID
ORDER BY ProgressData", connection)
cmd.Parameters.AddWithValue("@ID", rptID)
If connection.State <> ConnectionState.Open Then connection.Open()
reader = cmd.ExecuteReader()
If Not reader.HasRows Then
ft = New PdfFormattedText() With {.Font = New PdfFont("Tahoma", 10), .Color = secondaryColor}
ft.Clear()
ft.Append("No progress data available.")
page.Content.DrawText(ft, New PdfPoint(marginLeft, Y(startOffset)))
Return
End If
' Column widths — reduce Progress column so Status has more room
Dim col1 As Double = Math.Round(printableWidth * 0.5, 2) ' Progress
Dim col2 As Double = Math.Round(printableWidth * 0.05, 2) ' Pct
Dim col3 As Double = printableWidth - col1 - col2 ' Status (remaining)
' Header row (bold)
ft = New PdfFormattedText() With {.Font = headerFontBold, .Color = primaryColor}
ft.Clear()
ft.Append("Progress")
page.Content.DrawText(ft, New PdfPoint(marginLeft, Y(startOffset)))
ft.Clear()
ft.Font = headerFontBold
ft.Color = primaryColor
ft.Append("Pct")
page.Content.DrawText(ft, New PdfPoint(marginLeft + col1 + 8, Y(startOffset)))
ft.Clear()
ft.Font = headerFontBold
ft.Append("Status")
page.Content.DrawText(ft, New PdfPoint(marginLeft + col1 + col2 + 12, Y(startOffset)))
startOffset += 20
Dim rowPadding As Double = 6.0
Dim currentY As Double = startOffset
Dim availableHeight As Double = pageHeight - marginTop - marginBottom
While reader.Read()
Dim prog As String = If(reader.IsDBNull(0), "", reader.GetString(0))
Dim pct As String = If(reader.IsDBNull(1), "", reader.GetValue(1).ToString())
Dim stat As String = If(reader.IsDBNull(2), "", reader.GetString(2))
Dim bodyFt As New PdfFormattedText() With {.Font = bodyFont, .Color = PdfColors.Black}
' Wrap Progress and Status first so row height is based on the taller column
Dim progLines As List(Of String) = WrapTextToLines(page, prog, bodyFont, col1 - (rowPadding * 2))
Dim statLines As List(Of String) = WrapTextToLines(page, stat, bodyFont, col3 - (rowPadding * 2))
Dim linesCount As Integer = Math.Max(Math.Max(1, progLines.Count), Math.Max(1, statLines.Count))
Dim lineHeight As Double = bodyFont.Size + 4
Dim rowHeight As Double = linesCount * lineHeight + (rowPadding * 2)
If currentY + rowHeight > availableHeight Then
' new page (use same margins)
document.Pages.Add()
page = document.Pages(document.Pages.Count - 1)
crop = page.CropBox
pageHeight = crop.Height
baseTop = crop.Top - marginTop
Y = Function(offset) baseTop - offset
availableHeight = pageHeight - marginTop - marginBottom
currentY = startOffset
' redraw header on new page
ft = New PdfFormattedText() With {.Font = headerFontBold, .Color = primaryColor}
ft.Clear()
ft.Append("Progress")
page.Content.DrawText(ft, New PdfPoint(marginLeft, Y(startOffset)))
ft.Clear()
ft.Font = headerFontBold
ft.Color = primaryColor
ft.Append("Pct")
page.Content.DrawText(ft, New PdfPoint(marginLeft + col1 + 8, Y(startOffset)))
ft.Clear()
ft.Font = headerFontBold
ft.Append("Status")
page.Content.DrawText(ft, New PdfPoint(marginLeft + col1 + col2 + 12, Y(startOffset)))
End If
' Draw ProgressData lines (top->down)
Dim textY As Double = Y(currentY + rowPadding)
For i As Integer = 0 To progLines.Count - 1
bodyFt.Clear()
bodyFt.Append(progLines(i))
page.Content.DrawText(bodyFt, New PdfPoint(marginLeft, textY))
textY -= lineHeight
Next
' --- Pct: right-aligned in col2, keep % sign, bold, conditional color, never overflows ---
Dim pctRaw As String = If(String.IsNullOrWhiteSpace(pct), "", pct.Trim())
Dim pctNumeric As Double = 0
Dim pctToParse As String = pctRaw
If pctRaw.EndsWith("%"c) Then pctToParse = pctRaw.Substring(0, pctRaw.Length - 1).Trim()
Double.TryParse(pctToParse, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, pctNumeric)
Dim pctColor As System.Drawing.Color
If String.IsNullOrEmpty(pctRaw) Then
pctColor = System.Drawing.Color.Black
ElseIf pctNumeric >= 100 Then
pctColor = PercentHighColor
ElseIf pctNumeric >= 80 Then
pctColor = PercentMidColor
ElseIf pctNumeric >= 50 Then
pctColor = PercentLowColor
ElseIf pctNumeric > 0 Then
pctColor = PercentLowColor
Else
pctColor = System.Drawing.Color.Red
End If
Dim pctDisplay As String = If(String.IsNullOrEmpty(pctRaw), "-", pctRaw)
Dim pctMaxWidth As Double = col2 - (rowPadding * 2) - 2.0
' Try bold fonts/smaller sizes until it fits
Dim fittedPctFt As PdfFormattedText = Nothing
Dim fontCandidates() As String = {"Tahoma-Bold", "Arial-BoldMT", "Tahoma"}
For size = 10 To 6 Step -1
Dim found As Boolean = False
For Each fname In fontCandidates
Try
Dim fnt As New PdfFont(fname, size)
Dim tmp As New PdfFormattedText() With {.Font = fnt, .Color = ColorToPdf(pctColor)}
tmp.Clear()
tmp.Append(pctDisplay)
If tmp.Width <= pctMaxWidth Then
fittedPctFt = tmp
found = True
Exit For
End If
Catch
' ignore missing fonts
End Try
Next
If found Then Exit For
Next
' If still too wide, use smallest font and ellipsize
If fittedPctFt Is Nothing Then
Dim smallestFont As PdfFont
Try
smallestFont = New PdfFont("Tahoma", 6)
Catch
smallestFont = New PdfFont("Arial", 6)
End Try
fittedPctFt = New PdfFormattedText() With {.Font = smallestFont, .Color = ColorToPdf(pctColor)}
Dim disp As String = pctDisplay
fittedPctFt.Clear()
fittedPctFt.Append(disp)
While fittedPctFt.Width > pctMaxWidth AndAlso disp.Length > 1
disp = disp.Substring(0, disp.Length - 1)
fittedPctFt.Clear()
fittedPctFt.Append(disp & "…")
End While
End If
' Right-align inside Pct column (8pt right padding)
Dim pctRightEdge As Double = marginLeft + col1 + col2 - 8.0
Dim pctX As Double = pctRightEdge - fittedPctFt.Width
page.Content.DrawText(fittedPctFt, New PdfPoint(pctX, Y(currentY + rowPadding)))
' Draw Status lines (top->down) within col3
Dim statY As Double = Y(currentY + rowPadding)
For i As Integer = 0 To statLines.Count - 1
bodyFt.Clear()
bodyFt.Append(statLines(i))
page.Content.DrawText(bodyFt, New PdfPoint(marginLeft + col1 + col2 + 12, statY))
statY -= lineHeight
Next
currentY += rowHeight + 4
End While
Catch ex As Exception
ft = New PdfFormattedText() With {.Font = New PdfFont("Tahoma", 10), .Color = PdfColors.Red}
ft.Clear()
ft.Append("Error building report: " & ex.Message)
page.Content.DrawText(ft, New PdfPoint(marginLeft, Y(startOffset)))
Finally
If reader IsNot Nothing AndAlso Not reader.IsClosed Then reader.Close()
End Try
End Sub
Just outputs text on the page. How to make the loop into a table style, so the column header uses the background and highlights every 3rd row?? 1st time trying pdf creation??