windows forms printing problem. Won't print second page.

bh0526

Member
Joined
May 11, 2015
Messages
15
Programming Experience
10+
I'm really a C# web developer who suddenly was assigned a VB.Net Windows forms project. The last time i did VB was the 1990's. I'm struggling with printing using the printdocument control. It works fine if my data fits on one page. But now I have a list of orders that needs to print on 2 pages. I cannot get this to work. Presently, I get 3 pages of print but it's the exact same data on each page. I don't know how to use the e.HasMorePages property. It seems like I need to add the hasMorePages = true in the loop where I have the comment 'Print Orders. But I could not get it to work. I counted and it seems I can get 39 order lines on my report. This is in addition to the my header stuff. But after the 39th order prints, I want to skip to a new page, print headings again, and then continue with the 40th order and so on. Can anyone help me figure this out? Here is my code:
Code:
[/FONT][/COLOR][COLOR=#454545][FONT=Segoe UI]Public Sub OrderReport()[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]        Dim oOrder As New Order(connStringNW)[/FONT][/COLOR]

[COLOR=#454545][FONT=Segoe UI]        ' Loop thru all rows[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]        ds = SqlHelper.ExecuteDataset(connStringHG, "GetOrdersByOrderDates", DateTimePicker1.Value.ToShortDateString() + " 00:00:00.000",[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]                                                                             DateTimePicker2.Value.ToShortDateString() + " 23:59:59.999")[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]        For Each row As DataRow In ds.Tables(0).Rows[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]            lId.Add(CStr(row("Id")))[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]            lName.Add(CStr(row("CustomerName")))[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]            lTot.Add(CStr(row("OrderTotal")))[/FONT][/COLOR]

[COLOR=#454545][FONT=Segoe UI]            ' Select the printer[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]            Dim sDefaultPrinter As String = GetDefaultPrinterName()[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]            PrintDocument4.PrinterSettings.PrinterName = cboPrinter.Text[/FONT][/COLOR]

[COLOR=#454545][FONT=Segoe UI]            ' PrintDocument4.PrinterSettings.[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]            PrintDialog4.Document = PrintDocument4[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]            PrintDocument4.PrinterSettings.Copies = 1[/FONT][/COLOR]

[COLOR=#454545][FONT=Segoe UI]        Next[/FONT][/COLOR]

[COLOR=#454545][FONT=Segoe UI]        PrintDocument4.Print()[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]        btnExit.Visible = True[/FONT][/COLOR]

[COLOR=#454545][FONT=Segoe UI]    End Sub[/FONT][/COLOR]






[COLOR=#454545][FONT=Segoe UI]Private Sub PrintDocument4_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument4.PrintPage[/FONT][/COLOR]

[COLOR=#454545][FONT=Segoe UI]        Static loopIndex As Integer = 0[/FONT][/COLOR]

[COLOR=#454545][FONT=Segoe UI]        '------------------------------------------------------[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]        ' Set Fonts[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]        '------------------------------------------------------[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]        printFont18B = New Font("Tahoma", 18, FontStyle.Bold)[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]        printFont11B = New Font("Tahoma", 11, FontStyle.Bold)[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]        printFont18 = New Font("Tahoma", 18)[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]        printFont11 = New Font("Tahoma", 11)[/FONT][/COLOR]

[COLOR=#454545][FONT=Segoe UI]        iLine = 100

[/FONT][/COLOR]      iPageNum += 1        If iPageNum <= iTotalPages Then
            e.HasMorePages = True
        Else
            e.HasMorePages = False
            iPageNum = 0
        End If

[COLOR=#454545][FONT=Segoe UI]        '------------------------------------------------------[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]        ' Print Header Info[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]        '------------------------------------------------------[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]        e.Graphics.DrawString("Modern Robotics Inc.", printFont11B, Brushes.Black, 20, 30)[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]        e.Graphics.DrawString("Orders", printFont18B, Brushes.Black, 340, 20)[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]        e.Graphics.DrawString("Date: ", printFont11B, Brushes.Black, 660, 30)[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]        e.Graphics.DrawString(Today(), printFont11B, Brushes.Black, 710, 30)[/FONT][/COLOR]

[COLOR=#454545][FONT=Segoe UI]        e.Graphics.DrawString("From Start Date: ", printFont11B, Brushes.Black, 260, 65)[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]        e.Graphics.DrawString(DateTimePicker1.Value.ToShortDateString(), printFont11B, Brushes.Black, 400, 65)[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]        e.Graphics.DrawString("To: ", printFont11B, Brushes.Black, 495, 65)[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]        e.Graphics.DrawString(DateTimePicker2.Value.ToShortDateString(), printFont11B, Brushes.Black, 530, 65)[/FONT][/COLOR]

[COLOR=#454545][FONT=Segoe UI]        e.Graphics.DrawString("Order Id", printFont11B, Brushes.Black, 100, 110)[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]        e.Graphics.DrawString("Customer", printFont11B, Brushes.Black, 180, 110)[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]        e.Graphics.DrawString("Order Total", printFont11B, Brushes.Black, 555, 110)[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]        iLine = 140[/FONT][/COLOR]

[COLOR=#454545][FONT=Segoe UI]        ' Print Orders[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]        Dim j As Integer[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]        For j = 0 To lId.Count - 1[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]            e.Graphics.DrawString(lId(j).ToString(), printFont11, Brushes.Black, 100, iLine)[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]            e.Graphics.DrawString(lName(j).ToString(), printFont11, Brushes.Black, 180, iLine)[/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]            e.Graphics.DrawString(Format(Convert.ToSingle(lTot(j)), "0.00"), printFont11, Brushes.Black, 555, iLine)[/FONT][/COLOR]

[COLOR=#454545][FONT=Segoe UI]            iLine += 25[/FONT][/COLOR][COLOR=#454545][FONT=Segoe UI]        [/FONT][/COLOR]
[COLOR=#454545][FONT=Segoe UI]        Next j[/FONT][/COLOR]

[COLOR=#454545][FONT=Segoe UI]        iLine = 0[/FONT][/COLOR]

[COLOR=#454545][FONT=Segoe UI]    End Sub
[/FONT][/COLOR][COLOR=#454545][FONT=Segoe UI]
 

jmcilhinney

VB.NET Forum Moderator
Staff member
Joined
Aug 17, 2004
Messages
14,127
Location
Sydney, Australia
Programming Experience
10+
First of all, printing in C# is exactly the same as printing in VB, other than the language syntax. You use the exact same types and members.

So, you know that you need to use a PrintDocument object and you know that you have to handle the PrintPage event. Each time the PrintPage event is raised, one page is printed. If you want to print three pages then you have to raise the PrintPage event three times. Obviously it's the same code inside the event handler each time so you have to write that code such that it can determine what page it is supposed to be printing and then retrieve and draw the data for that page. Setting the e.HasMorePages property is generally the last thing you do in the event handler. You draw the data to be printed for the current page and then you determine whether there is more data to print. If there is then you set e.HasMorePages to True and the PrintPage event will be raised again to print another page. If there is no more data to print then you either set it to False or don't set it at all and accept the default value of False, in which case no more PrintPage events are raised and the print job ends. Here's a simple example that prints the items from a collection, one to a page:
Private items As New List(Of String)

Private itemIndex As Integer

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Me.PrintDocument1.Print()
End Sub

Private Sub PrintDocument1_BeginPrint(sender As Object, e As Printing.PrintEventArgs) Handles PrintDocument1.BeginPrint
    'Reset the item index at the beginning of a print run.
    Me.itemIndex = 0
End Sub

Private Sub PrintDocument1_PrintPage(sender As Object, e As Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
    'Print the current item.
    e.Graphics.DrawString(Me.items(Me.itemIndex), Me.Font, Brushes.Black, Point.Empty)

    'Advance to the next tiem.
    Me.itemIndex += 1

    'Keep printing if and only if we have not passed the end of the collection.
    e.HasMorePages = (Me.itemIndex < Me.items.Count)
End Sub
 

bh0526

Member
Joined
May 11, 2015
Messages
15
Programming Experience
10+
Thanks for your reply.

It's not a C# or VB.Net thing for me as I develop using both languages. It's that I have not written a VB.Net windows forms program in 20 years. And I have never done printing like this and I'm pretty much clueless. I always use SQL Server Reporting Services but my client won't allow this. So I tried your solution but now nothing prints. The problem with my code seems be in this section:

' Print Orders
Dim j As Integer
For j = 0 To lId.Count - 1
e.Graphics.DrawString(lId(j).ToString(), printFont11, Brushes.Black, 100, iLine)
e.Graphics.DrawString(lName(j).ToString(), printFont11, Brushes.Black, 180, iLine)
e.Graphics.DrawString(Format(Convert.ToSingle(lTot(j)), "0.00"), printFont11, Brushes.Black, 555, iLine)


iLine += 25
Next j

It prints my first set of orders perfectly on the first page. But then it prints the exact same page 2 more times. What I want it to do is print the second page of orders after it prints the last line of the first page. I don't know how to do this using the code you suggested. I tried putting your code in the For / Next loop but then i get no print output at all.
 

IanRyder

Well-known member
Joined
Sep 9, 2012
Messages
1,130
Location
Healing, NE Lincs, UK
Programming Experience
10+
Hi,

To expand on what you have already been shown and to demonstrate how these principles work then have a look at this:-

Create a list of some sort:-
Private listItems As New List(Of String)
Private listIndex As Integer
 
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
  For counter As Integer = 1 To 300
      listItems.Add(String.Format("This is Line Number {0} In the Document.", counter))
  Next
 
  PrintPreviewControl1.Document = PrintDocument1
End Sub


Reset the listIndex Variable in the BeginPrint Event:-
Private Sub PrintDocument1_BeginPrint(sender As Object, e As Printing.PrintEventArgs) Handles PrintDocument1.BeginPrint
  listIndex = 0
End Sub


Finally, print the entire list to multiple pages of a PrintDocument based on the Available Space defined by the Margins of the PrintDocument:-
Private Sub PrintDocument1_PrintPage(sender As Object, e As Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
  Dim currentPrintRect As New Rectangle(e.MarginBounds.X, e.MarginBounds.Y, e.MarginBounds.Width, e.MarginBounds.Height)
  Using printFont As New Font("Ariel", 15, FontStyle.Bold)
    Do While currentPrintRect.Top + printFont.Height <= e.MarginBounds.Bottom AndAlso listIndex <= listItems.Count - 1
      e.Graphics.DrawString(listItems(listIndex), printFont, Brushes.Black, currentPrintRect)
      currentPrintRect.Offset(0, printFont.Height + 2)
      listIndex += 1
    Loop
 
    If listIndex <= listItems.Count - 1 Then
      e.HasMorePages = True
    End If
  End Using
End Sub


Hope that helps.

Cheers,

Ian
 

bh0526

Member
Joined
May 11, 2015
Messages
15
Programming Experience
10+
Ian,

Thanks for the reply. I changed my code like this:

' Print Orders
Do While listIndex <= lId.Count - 1
e.Graphics.DrawString(lId(j).ToString(), printFont11, Brushes.Black, 100, iLine)
e.Graphics.DrawString(lName(j).ToString(), printFont11, Brushes.Black, 180, iLine)
e.Graphics.DrawString(Format(Convert.ToSingle(lTot(j)), "0.00"), printFont11, Brushes.Black, 555, iLine)


listIndex += 1


iLine += 25
Loop


If listIndex <= lId.Count - 1 Then
e.HasMorePages = True
End If


iLine = 0


But now I get no print output.
 

Herman

Well-known member
Joined
Oct 18, 2011
Messages
882
Location
Montreal, QC, CA
Programming Experience
10+
It's not a C# or VB.Net thing for me as I develop using both languages. It's that I have not written a VB.Net windows forms program in 20 years.
In 1990 there was no VB.NET, there was only classic VB. Whole different beast. So, you have probably never worked at all with VB.NET from your replies. If you want to make it simple, just write it in C# if you are more comfortable in it. Then go through a C# to VB.NET converter like this one: Code Converter | Provided by Telerik . It will give you a pretty good idea of how the code should look like. C# and VB.NET are the same meal in different flavors. Most of the code will be identical except for language specific syntax.
 

bh0526

Member
Joined
May 11, 2015
Messages
15
Programming Experience
10+
Yes, I started with .Net with the beta version in 2000. I meant VB6 or whatever number it was in 1996. But along those lines, I have never written a VB.Net windows forms program until now. I can't write it in C# since the client is requiring VB.Net since that is what their staff knows. But that is not the problem. it's not a VB / C# thing. I know both. I have never used this PrintDocument control and struggling with it. I only need help with PrintDocument code. I don't care if the posted help is in C# or VB.Net.
 
Last edited:

IanRyder

Well-known member
Joined
Sep 9, 2012
Messages
1,130
Location
Healing, NE Lincs, UK
Programming Experience
10+
Hi,

The bit that gets me is that since you are an experienced developer and regardless of whether this is in VB or C#, you seem to be struggling with replicating simple concepts that you can then re-engineer to accommodate your own needs. As an experienced developer, you should always take the time to read the documentation for new class objects that you have not dealt with before and therefore, to sort that, start with the link below and then post back if you are still struggling:-

PrintDocument Class

Cheers,

Ian
 

bh0526

Member
Joined
May 11, 2015
Messages
15
Programming Experience
10+
Yeah, I don't like this PrintDocument. Maybe it's just me but it seems strange. And don't forget that I did originally write the code that produced the report without ever using PrintDocument. But now my client it generating hundreds of orders a day which means multiple pages are being produced. The part that I'm struggling with is the HasMorePages property. Obviously my code does not work, and no offense, but no one else's solutions has worked either.

SSRS is what we use for all reporting needs when we build our web sites. But this client won't allow me to use this reporting tool.

Also, I have been posting code since my original post. No one has been able to identify where I'm going wrong. I've tried several solutions that were posted here but no luck yet.
 

Herman

Well-known member
Joined
Oct 18, 2011
Messages
882
Location
Montreal, QC, CA
Programming Experience
10+
Have you tried debugging it and validating each step of the process? One of your variables is probably not being initialized properly or something similar. Set a breakpoint at the first line of the printing process, and step through the code while checking the contents of each variable. I bet you will find one of them does not contain what it should after the first page printed.
 

bh0526

Member
Joined
May 11, 2015
Messages
15
Programming Experience
10+
Herman,

I stepped thru the code several times already but with all my recent changes, I did it again as you suggested. As I step thru this code:

' Print Orders
Dim j As Integer
For j = 0 To lId.Count - 1
e.Graphics.DrawString(lId(j).ToString(), printFont11, Brushes.Black, 100, iLine)
e.Graphics.DrawString(lName(j).ToString(), printFont11, Brushes.Black, 180, iLine)
e.Graphics.DrawString(Format(Convert.ToSingle(lTot(j)), "0.00"), printFont11, Brushes.Black, 555, iLine)


listIndex += 1


iLine += 25
Next j

I see all 70 of my orders that I want to print. I removed my e.HasMorePages = True. So at this point, I only get my first page and that's it. 39 orders fit on my printed page. So now I want to print the remaining 31 orders on a new page. This is where I'm having problems. I'm not exactly sure where / how I set e.HasMorePages = True.
 

Herman

Well-known member
Joined
Oct 18, 2011
Messages
882
Location
Montreal, QC, CA
Programming Experience
10+
Can you please post ALL your code, together, in a neat one-shot copy paste? From the start we are trying to decipher partial snippets of code to help you out, but it's not really productive, and wastes everyone's time. From what I can gather your code looks something like this:

    Public Sub OrderReport()
        Dim oOrder As New Order(connStringNW)

        ' Loop thru all rows
        ds = SqlHelper.ExecuteDataset(connStringHG, "GetOrdersByOrderDates", DateTimePicker1.Value.ToShortDateString() + " 00:00:00.000",
                                                                             DateTimePicker2.Value.ToShortDateString() + " 23:59:59.999")
        For Each row As DataRow In ds.Tables(0).Rows
            lId.Add(CStr(row("Id")))
            lName.Add(CStr(row("CustomerName")))
            lTot.Add(CStr(row("OrderTotal")))

            ' Select the printer
            Dim sDefaultPrinter As String = GetDefaultPrinterName()
            PrintDocument4.PrinterSettings.PrinterName = cboPrinter.Text

            ' PrintDocument4.PrinterSettings.
            PrintDialog4.Document = PrintDocument4
            PrintDocument4.PrinterSettings.Copies = 1

        Next

        PrintDocument4.Print()
        btnExit.Visible = True

    End Sub
    
    
    Private Sub PrintDocument4_PrintPage(ByVal sender As Object, Byval e As PrintPageEventArgs)
        ' ... some other code ??? ...
        
        ' Print Orders
        Dim j As Integer
        For j = 0 To lId.Count - 1
            e.Graphics.DrawString(lId(j).ToString(), printFont11, Brushes.Black, 100, iLine)
            e.Graphics.DrawString(lName(j).ToString(), printFont11, Brushes.Black, 180, iLine)
            e.Graphics.DrawString(Format(Convert.ToSingle(lTot (j)), "0.00"), printFont11, Brushes.Black, 555, iLine)

            listIndex += 1

            iLine += 25
        Next j
    End Sub


There is still missing chunks in there, so please post your real code, without edition. I will try to help you a bit more...
 

bh0526

Member
Joined
May 11, 2015
Messages
15
Programming Experience
10+
The problem is this client does crazy things like producing 5 different reports from one windows forms program. I am only concerned with this orders report. Let me copy everything over to notepad and then delete the code for the other 4 reports since they work ok. Give me a few minutes.
 

bh0526

Member
Joined
May 11, 2015
Messages
15
Programming Experience
10+
Here is the code for the Orders report. You will notice a lot of variables defined at the top of code. Many are unused for my specific report but are used for the other 4 reports. I left them in for time's sake. Here is the complete code:

Imports System.Configuration
Imports OrdersClasses
Imports System.Data
Imports System.Data.SqlClient
Imports System
Imports System.IO
Imports System.Drawing
Imports System.Drawing.Printing
Imports System.Drawing.Bitmap
Imports System.Windows.Forms
Imports System.Management
Imports Microsoft.ApplicationBlocks.Data


Public Class SalesReportAll


Dim connStringHG As String = ConfigurationManager.ConnectionStrings("MRIhg").ConnectionString
Dim connStringNW As String = ConfigurationManager.ConnectionStrings("MRInw").ConnectionString


Dim ds As New DataSet()
Dim dt As New DataTable()


Dim printFont18B As Font
Dim printFont11B As Font
Dim printFont18 As Font
Dim printFont11 As Font
Dim printFont8 As Font
Dim printFont3of9 As Font


Dim iLine As Integer = 170


' List controls
Dim lState As List(Of String) = New List(Of String)
Dim lPct As List(Of String) = New List(Of String)
Dim lSku As List(Of String) = New List(Of String)
Dim lDesc As List(Of String) = New List(Of String)
Dim lQty As List(Of String) = New List(Of String)
Dim lPri As List(Of String) = New List(Of String)
Dim lAmount As List(Of String) = New List(Of String)
Dim lTaxAmount As List(Of String) = New List(Of String)
Dim lTaxCode As List(Of String) = New List(Of String)


Dim lId As List(Of String) = New List(Of String)
Dim lName As List(Of String) = New List(Of String)
Dim lTot As List(Of String) = New List(Of String)


Dim TotalAmount As Single
Dim TotalTax As Single


Dim ShippingAmount As Single = 0
Dim TotalShippingAmount As Single = 0


Dim GrandTotalAmount = 0


Dim sLastPayType As String = ""
Dim ppGross As Single = 0
Dim ppFees As Single = 0
Dim ppNet As Single = 0


Dim PayType As String = ""
Dim sngGross As Single = 0
Dim sngFees As Single = 0
Dim sngNet As Single = 0


Dim sngPayTypeGross As Single = 0
Dim sngPayTypeFees As Single = 0
Dim sngPayTypeNet As Single = 0


Dim iTotalPages As Integer = 0
Dim iPageNum As Integer


Private listIndex As Integer


Private Sub Form3_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
End Sub


' List the available printers.
Private Sub Form1_Load(ByVal sender As System.Object, ByVal _
e As System.EventArgs) Handles MyBase.Load


For Each printer As String In _
PrinterSettings.InstalledPrinters
cboPrinter.Items.Add(printer)
Next printer


cboPrinter.SelectedText = GetDefaultPrinterName()
End Sub


Private Sub btnPrint_Click(sender As Object, e As EventArgs) Handles btnPrint.Click

OrderReport()


btnExit.Visible = True


End Sub


Private Sub PrintDocument4_BeginPrint(sender As Object, e As Printing.PrintEventArgs) Handles PrintDocument4.BeginPrint
listIndex = 0
End Sub


Private Sub PrintDocument4_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument4.PrintPage


Static loopIndex As Integer = 0


'------------------------------------------------------
' Set Fonts
'------------------------------------------------------
printFont18B = New Font("Tahoma", 18, FontStyle.Bold)
printFont11B = New Font("Tahoma", 11, FontStyle.Bold)
printFont18 = New Font("Tahoma", 18)
printFont11 = New Font("Tahoma", 11)


iLine = 100


'Advance to the next tiem.
listIndex += 1


'If Me.itemIndex < iTotalPages Then
' e.HasMorePages = (Me.itemIndex < iTotalPages)
'End If


'iPageNum += 1
'If iPageNum <= iTotalPages Then
' e.HasMorePages = True
'Else
' e.HasMorePages = False
' iPageNum = 0
'End If


'------------------------------------------------------
' Print Header Info
'------------------------------------------------------
e.Graphics.DrawString("Modern Robotics Inc.", printFont11B, Brushes.Black, 20, 30)
e.Graphics.DrawString("Orders", printFont18B, Brushes.Black, 340, 20)
e.Graphics.DrawString("Date: ", printFont11B, Brushes.Black, 660, 30)
e.Graphics.DrawString(Today(), printFont11B, Brushes.Black, 710, 30)


e.Graphics.DrawString("From Start Date: ", printFont11B, Brushes.Black, 260, 65)
e.Graphics.DrawString(DateTimePicker1.Value.ToShortDateString(), printFont11B, Brushes.Black, 400, 65)
e.Graphics.DrawString("To: ", printFont11B, Brushes.Black, 495, 65)
e.Graphics.DrawString(DateTimePicker2.Value.ToShortDateString(), printFont11B, Brushes.Black, 530, 65)


e.Graphics.DrawString("Order Id", printFont11B, Brushes.Black, 100, 95)
e.Graphics.DrawString("Customer", printFont11B, Brushes.Black, 180, 95)
e.Graphics.DrawString("Order Total", printFont11B, Brushes.Black, 555, 95)
iLine = 125


' Print Orders
Dim j As Integer
For j = 0 To lId.Count - 1
e.Graphics.DrawString(lId(j).ToString(), printFont11, Brushes.Black, 100, iLine)
e.Graphics.DrawString(lName(j).ToString(), printFont11, Brushes.Black, 180, iLine)
e.Graphics.DrawString(Format(Convert.ToSingle(lTot(j)), "0.00"), printFont11, Brushes.Black, 555, iLine)


listIndex += 1


iLine += 25
Next j


If listIndex <= lId.Count - 1 Then
e.HasMorePages = True
End If


iLine = 0


End Sub


Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnExit.Click
btnExit.Visible = False
Me.Dispose()
End Sub




Public Shared Function GetDefaultPrinterName() As String
Dim query = New ObjectQuery("SELECT * FROM Win32_Printer")
Dim searcher = New ManagementObjectSearcher(query)


For Each mo As ManagementObject In searcher.[Get]()
If If(CType(mo("Default"), System.Nullable(Of Boolean)), False) Then
Return TryCast(mo("Name"), String)
End If
Next


Return Nothing
End Function


Public Sub OrderReport()
Dim oOrder As New Order(connStringNW)


Dim sStartDate As String
Dim sEndDate As String


sStartDate = DateTimePicker1.Value.ToShortDateString() + " 00:00:00.000"
sEndDate = DateTimePicker2.Value.ToShortDateString() + " 23:59:59.999"


' Loop thru all rows
'ds = SqlHelper.ExecuteDataset(connStringHG, "GetOrdersByOrderDates", DateTimePicker1.Value.ToShortDateString() + " 00:00:00.000",
' DateTimePicker2.Value.ToShortDateString() + " 23:59:59.999")
ds = SqlHelper.ExecuteDataset(connStringHG, "GetOrdersByOrderDates", Convert.ToDateTime(sStartDate),
Convert.ToDateTime(sEndDate))
For Each row As DataRow In ds.Tables(0).Rows
lId.Add(CStr(row("Id")))
lName.Add(CStr(row("CustomerName")))
lTot.Add(CStr(row("OrderTotal")))


' Select the printer
Dim sDefaultPrinter As String = GetDefaultPrinterName()
PrintDocument4.PrinterSettings.PrinterName = cboPrinter.Text


' PrintDocument4.PrinterSettings.
PrintDialog4.Document = PrintDocument4
PrintDocument4.PrinterSettings.Copies = 1
Next


iTotalPages = ds.Tables(0).Rows.Count / 37


PrintDocument4.Print()
btnExit.Visible = True


End Sub


Public Function GetGrossByPayType(str As String) As DataTable


Dim result() As DataRow = dt.Select("PaymentType = " & "'" & str & "'")


Dim sngGross As Single = 0
Dim sngFees As Single = 0
Dim sngNet As Single = 0


For Each row As DataRow In result
sngGross += Convert.ToSingle(row("GrossAmt"))
sngFees += Convert.ToSingle(row("FeesAmt"))
sngNet += Convert.ToSingle(row("NetAmt"))
Next


Dim dtrow As New DataTable
dtrow.Columns.Add("Gross", GetType(Single))
dtrow.Columns.Add("Fees", GetType(Single))
dtrow.Columns.Add("Net", GetType(Single))


If sngGross = 0 Then
' Do nothing
Else
dtrow.Rows.Add(sngGross, sngFees, sngNet)
End If


Return dtrow


End Function


Public Function GetShipAmt(str As Object) As Single


If str Is DBNull.Value Then
Return 0
Else
Return Convert.ToSingle(str)
End If


End Function


End Class
 
Last edited:

Herman

Well-known member
Joined
Oct 18, 2011
Messages
882
Location
Montreal, QC, CA
Programming Experience
10+
Ouch my eyes... This is clearly really old VB6 code that was updated and patched but never properly rewritten to take advantage of object orientation. The heavy use of globals will make this code extremely hard to work with.

I have to admit I did not expect printing some text to be so challenging, but I expect MS did this on purpose, not to steal business from components suppliers in the reporting business. Here is what I came up with, much more object oriented:

Public Class OrderReport
    Private _rows As New List(Of OrderReportRow)

    Public Property HtmlTableTemplate As String = "<html><body><table style=""width:100%"">{0}</table></body></html>"

    Public Property SourceTable As DataTable = Nothing


    Private Sub GetData()
        If SourceTable IsNot Nothing Then
            _rows = New List(Of OrderReportRow)

            For Each row As DataRow In SourceTable.Rows
                _rows.Add(New OrderReportRow() With {.Id = CStr(row("Id")),
                                                     .Name = CStr(row("CustomerName")),
                                                     .Total = CStr(row("OrderTotal"))})
            Next
        End If
    End Sub


    Public Function GetHtml() As String
        Dim htmlRows = ""
        For Each row In _rows
            htmlRows += row.GetHtml()
        Next
        Return String.Format(HtmlTableTemplate, htmlRows)
    End Function


    Public Sub Print()
        GetData()

        Dim wb As New WebBrowser()
        wb.Navigate("about:blank")
        Dim htmlDoc = wb.Document.OpenNew(True)
        htmlDoc.Write(Me.GetHtml())

        wb.ShowPrintPreviewDialog()
    End Sub


    Public Sub PrintPreview()
        GetData()

        Dim wb As New WebBrowser()
        wb.Navigate("about:blank")
        Dim htmlDoc = wb.Document.OpenNew(True)
        htmlDoc.Write(Me.GetHtml())

        wb.ShowPrintDialog()
    End Sub


    Public Class OrderReportRow
        Public Property Id As String
        Public Property Name As String
        Public Property Total As String

        Public Property HtmlRowTemplate As String = "<tr><td>{0}</td><td>{1}</td><td>{2}</td></tr>"

        Public Function GetHtml() As String
            Return String.Format("<tr><td>{0}</td><td>{1}</td><td>{2}</td></tr>", Id, Name, Total)
        End Function
    End Class

End Class


You bind a datatable to this and give it a HTML template, and it uses the WebBrowser control to provide printing and print preview. And you can use it like this:

        Dim r = New OrderReport()

        Dim dt As New DataTable
        dt.Columns.Add("Id")
        dt.Columns.Add("CustomerName")
        dt.Columns.Add("OrderTotal")

        dt.Rows.Add({"ASDFADF", "ASDFASDFASDF", "SFGHDGFHDFG"})
        dt.Rows.Add({"ASDFADF", "ASDFASDFASDF", "SFGHDGFHDFG"})
        dt.Rows.Add({"ASDFADF", "ASDFASDFASDF", "SFGHDGFHDFG"})
        dt.Rows.Add({"ASDFADF", "ASDFASDFASDF", "SFGHDGFHDFG"})
        dt.Rows.Add({"ASDFADF", "ASDFASDFASDF", "SFGHDGFHDFG"})
        dt.Rows.Add({"ASDFADF", "ASDFASDFASDF", "SFGHDGFHDFG"})
        dt.Rows.Add({"ASDFADF", "ASDFASDFASDF", "SFGHDGFHDFG"})
        dt.Rows.Add({"ASDFADF", "ASDFASDFASDF", "SFGHDGFHDFG"})
        dt.Rows.Add({"ASDFADF", "ASDFASDFASDF", "SFGHDGFHDFG"})
        dt.Rows.Add({"ASDFADF", "ASDFASDFASDF", "SFGHDGFHDFG"})
        dt.Rows.Add({"ASDFADF", "ASDFASDFASDF", "SFGHDGFHDFG"})
        dt.Rows.Add({"ASDFADF", "ASDFASDFASDF", "SFGHDGFHDFG"})

        r.SourceTable = dt

        r.Print()
 

bh0526

Member
Joined
May 11, 2015
Messages
15
Programming Experience
10+
Yeah, the IT director at my client is a dinosaur. They are forever stuck in the VB6 world. If you look at my Imports, I have a reference named OrderClasses which contains all my classes with properties, methods, constructors, etc for the order entry system. When the guy saw that, he demanded that I remove it since his staff would be confused. So I do use the Microsoft Application Data Blocks which simply encapsulates the ADO.Net code and allows data access to the SQL db with one line of code. But I hope he does not see that since he would probably make me get rid of that as well. Luckily, he does not put any restrictions on me when I built their web site. I use MVC 5 for that. I would not even work with this client if he restricted my web development.

I'll try your suggestions.
 

Herman

Well-known member
Joined
Oct 18, 2011
Messages
882
Location
Montreal, QC, CA
Programming Experience
10+
Why would his staff even be in the source code, are they programmers? If not I would honestly just tell him he's out of his league, politely. You should be able to do your job without artificial and nonsensical restrictions. Not using SSRS or avoiding external libraries you don't have the source to is a reasonable restriction, but telling you how to factor your own code is rude and none of his business, especially considering the state of the existing code...
 

bh0526

Member
Joined
May 11, 2015
Messages
15
Programming Experience
10+
He has a staff of programmers. But they have never gotten into .Net. I use my class library, OrderClasses, for their web site. So I spent a lot of time creating this. It's their code, not mine as I developed it for them. They own the source code. I told him it's not a difficult concept to teach his staff but he said they don't have time. I've billed this client several hundred $$$ over the last 2 years so I just do what I'm told. Problem is, I suck at windows development. I'm almost done with this client and will get back to web development soon.
 

bh0526

Member
Joined
May 11, 2015
Messages
15
Programming Experience
10+
I was able to get this working. If anyone is interested, here is my code:

' Print Orders
Dim j As Integer
Dim row As Integer = e.MarginBounds.Top

For i As Integer = index To lId.Count - 1
e.Graphics.DrawString(lId(i).ToString(), printFont11, Brushes.Black, 100, iLine)
e.Graphics.DrawString(lName(i).ToString(), printFont11, Brushes.Black, 180, iLine)
e.Graphics.DrawString(Format(Convert.ToSingle(lTot(i)), "0.00"), printFont11, Brushes.Black, 555, iLine)

iLine += 25

index = i
row += 20
If row > e.MarginBounds.Bottom - 120 Then
e.HasMorePages = True
Exit Sub
Else
'continue printing
End If

Next

I'm not a big fan of this type of printing. SSRS is much more powerful / easier and comes with SQL. All my customers use SQL database and they all embraced SSRS. But this one particular client will not use it since they live in the past.
 

jmcilhinney

VB.NET Forum Moderator
Staff member
Joined
Aug 17, 2004
Messages
14,127
Location
Sydney, Australia
Programming Experience
10+
More powerful? I'm afraid that you simply don't know what you're talking about. Using a PrintDocument you can print anything that you can draw using GDI+. The fact is that you simply don't know how to use it properly. That's fine but, while using SSRS may be easier for things that SSRS can display, to say that it's more powerful is simply ignorant.
 
Top Bottom