Format a Document for Printing

Posted on 2005-03-08
Medium Priority
Last Modified: 2012-06-27
Does anyone have any good links/information on how to format a document for printing within VB.NET?

Thanks in advance,

Question by:Rorc
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 4
LVL 15

Accepted Solution

Ralf Klatt earned 1500 total points
ID: 13490612

Assuming that you're getting your data to print from a DataSet I'd suggest to read the following article:

How do I print a DataSet in VB.NET?
This page contains the source code for my PrintHandler class that you can add to your project to print the contents of a Dataset in a report format. The PrintHandler:

Prints and/or Previews all rows of the specified table in your dataset.

Allows you to display the standard Window's Page Setup Dialog.

Does not print DataSet rows flagged as deleted.

Only prints rows passing the filter criteria if the DataSet is filtered.

Wraps columns to the next page if there are more columns than can fit on a page.

Let's you set the report's title (the default is the specified table's name).

Let's you set the number of columns to print (the default is all columns).

Exposes a line threshold property which, if exceeded, prompts for confirmation before printing a large DataSet.

Allows you to control printed column width by resizing the corresponding columns in the DataGrid bound to the DataSet.

Lets you specify column captions (column names of the specified table are used by default).

Catches and re-throws all exceptions so they can be caught by the calling module.


PrintHandler is designed to print a DataSet that's bound to a DataGrid. Typical usage is to display data in a DataGrid, format the DataGrid's columns and present a way for the user to call the PrintHandler's methods.

To format a DataGrid you add a GridColumnStyle for each column to a GridTableStyle then associate the GridTableStyle with the DataGrid. PrintHandler uses the GridColumnStyle's HeaderText value as the caption for a column. If the HeaderText value is not set the actual column name is used.

Users control the width of printed columns by resizing the corresponding columns in the DataGrid. Columns whose width is zero (e.g. not visible in the DataGrid) are not printed. Inital column widths can be set via the GridColumnStyle objects.

Here's an example of a DataGrid with 3 columns. Column 1 is the Customer_Name which PrintHandler will caption Customer due to the HeaderText value. Column 2 will not be printed because its width is zero. The actual column name of Customer_Address will be used for column 3 since the HeaderText is not set.

    ' Create a GridTableStyle and set its MappingName to the name of the DataTable.
    Dim aGridTableStyle As New DataGridTableStyle
    aGridTableStyle.MappingName = "Customers"
    ' Create GridColumnStyle objects for the grid columns.
    Dim aCol1 As New DataGridTextBoxColumn
    Dim aCol2 As New DataGridTextBoxColumn
    Dim aCol2 As New DataGridTextBoxColumn

    aCol1.MappingName = "Customer_Name"  
    aCol1.HeaderText = "Customer"        
    aCol1.Width = 75                    
    aCol1.Alignment = HorizontalAlignment.Left

    aCol2.MappingName = "Customer_Number"
    aCol2.Width = 0

    aCol3.MappingName = "Customer_Address"
    aCol3.Width = 100
    aCol3.Alignment = HorizontalAlignment.Left
    ' Add the GridColumnStyles to the GridTableStyle.

To call the PrintHandler to Print or Preview the data:

PrintHandler receives the DataSet to print as a parameter. However, HeaderText and column width values are associated with GridColumnStyles and not the DataSet itself so this information is lost. To preserve it, the Caption property of the DataSet's columns is set and an ExtendedProperty is created for each column to hold its width.

    Dim aCol As Integer
    Dim aTblIndex As Integer = 0
    Dim aNumColumns As Integer
    Dim aColumnStyles As GridColumnStylesCollection
        ' The dataset may have columns not displayed in the grid. Looping through
        ' GridColumnStyles errors when the number of GridColumnStyles is exceeded.
        ' The error is caught and the number of displayed columns is adjusted. The
        ' GridColumnStyles collection doesn't expose a Count property nor does the
        ' DataGrid expose the number of displayed columns.
        aColumnStyles = DataGrid.TableStyles(aTblIndex).GridColumnStyles
        aNumColumns = myDataSet.Tables(aTblIndex).Columns.Count - 1

        With myDataSet.Tables(aTblIndex)
            For aCol = 0 To aNumColumns
                .Columns(aCol).Caption = aColumnStyles.Item(aCol).HeaderText

                If theColumnStyles.Item(aCol).Width = 0 Then
                    .Columns.Item(aCol).ExtendedProperties.Add("PrintWidth", -1)
                    .Columns.Item(aCol).ExtendedProperties.Add( _
                        "PrintWidth", aColumnStyles.Item(aCol).Width)
                End If
        End With

    Catch Ex As System.ArgumentOutOfRangeException
        aNumColumns = aCol- 1

    Catch Ex As Exception
        Throw New Exception("Error setting column captions.", Ex)

    End Try

    ' Call the PrintHandler.
    Dim aPrintObj As New PrintHandler

    With aPrintObj
        .LineThreshold = 500
        .NumberOfColumns = aNumColumns
        .DataSetToPrint = myDataSet
        .ReportTitle = "Customer List"
        .DataSetToPrint = myDataSet
        .TableIndex = aTblIndex

        If blnPreview Then
        End If
    End With

    aPrintObj = Nothing

To display the Print Setup Dialog:

    Dim aPrintObj As New PrintHandler
    aPrintObj = Nothing


Printing in VB.NET is based on a PrintDocument from the System.Drawing.Printing namespace which sends output to a printer similar to VB6's Printer Object. A variable is defined as a PrintDocument and declared WithEvents so you can react to its events.

To display Window's Page Setup Dialog PrintHandler uses code similar to:

    Private WithEvents myDocumentToPrint As PrintDocument

    Dim aPS As New PageSetupDialog
    aPS.Document = myDocumentToPrint
    ' On the 1-rst call to the print dialog initialize the document's
    ' properties. On subsequent calls use what was previously set.
    If Not myPageSetUp Then
        With aPS.Document.DefaultPageSettings
            .Margins.Top = 50
            .Margins.Left = 50
            .Margins.Right = 50
            .Margins.Bottom = 50
            .Landscape = True
        End With
    End If

The PrintHandler's Preview method verifies the DataSet has data then calls the preceeding PageSetupDialog code to initialize the PrintDocument if necessary. An instance of a PrintPreviewDialog class is created and passed the PrintDocument. Finally the PrintPreviewDialog's ShowDialog method is called:

    Dim aPrevDialog As New PrintPreviewDialog

    aPrevDialog.Document = myDocumentToPrint

Similarly, the PrintHandler's Print method verifies the DataSet has data. If it has more rows than the LineThreshold value a print confirmation is issued. Once the decision to print is made the above PageSetupDialog code is conditionally called. Lastly, printing is performed by calling the PrintDocument's Print method:


Actual printing logic resides in the PrintDocument's PrintPage Event. PrintPage is a Callback Event called by Windows repeatedly whenever the PrintDocument's Print or Preview methods are called. PrintPage is called until the HasMorePages property of its PrintPageEventArgs parameter is set False.

See the source code for the gory details of this event. Basically, this code creates a generic report header line using the report title that was passed in. The width of the PrintDocument page is determined and the header line is centered within it.

A DataRow is retrieved from the DataSet and the columns are enumerated in a loop. If the column width stored in the PrintWidth ExtendedProperty is greater than zero the column's caption is printed. As stated earlier, if the caption property was not set the actual column name is used. Additionally, if the PrintWidth ExtendedProperty was not set, the width of the resultant column caption is used.

Once the heading of the report has been printed a nested loop is entered to print the dataset's data. The outside loop processes the rows while the inner loop prints the values of the columns in the row. Checks are performed to skip rows marked as deleted and to see if the number of lines (rows) printed exceed the number of lines that can fit on a page.

If the data spans pages the PrintDocument's PrintPageEventArgs' HasMorePages property is set. When all DataRows have been printed the HasMorePages propery is set False spooling the output to the printer.

Again, see the source code for all the details.

By the way (and just in case the link won't be there anymore in future) ... I've copied the article from: http://www.thescarms.com/dotNet/PrintDataSet.asp

Best regards,

Author Comment

ID: 13491437
That helps explian somewhat, but what I'm trying to do is:

Take data from my objects (the objects each contain 8 entries and are in an array)

Format this so that my sheet will look something like:

Object1.ItemA                   Object.ItemB
Object1.ItemC                   Object.ItemD
LVL 15

Expert Comment

by:Ralf Klatt
ID: 13491517

Your question was "Does anyone have any good links/information on how to format a document for printing within VB.NET?" and I provided a link that helped explain ... if you have problems with an array then please provide the code you've already prepared so I may have a look on it ...

Best regards,
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!


Author Comment

ID: 13492321
This is the item I am trying to print:
TheTest(i).Question = DataBank.Tables(0).Rows(CurrentQuestion).Item(1)
TheTest(i).OptionA = DataBank.Tables(0).Rows(CurrentQuestion).Item(2)
TheTest(i).OptionB = DataBank.Tables(0).Rows(CurrentQuestion).Item(3)
TheTest(i).OptionC = DataBank.Tables(0).Rows(CurrentQuestion).Item(4)
TheTest(i).OptionD = DataBank.Tables(0).Rows(CurrentQuestion).Item(5)
TheTest(i).Answer = DataBank.Tables(0).Rows(CurrentQuestion).Item(6)

TheTest(i) is an array of a user defined objects (Questions)
The question contains 8 items, Question, 4 options, the answer, the user's selection, and a flag to say if the user has already answered the question

My final printout should result in an output as such:

Option 1                   Option 2
Option 3                   Option 4

The user's selection

then the correct answer

sorry if there was any confusion.

Author Comment

ID: 13492329
oh, I forgot to mention, I dump the Databank.Tables(0) object after I finish reading from it.
LVL 15

Expert Comment

by:Ralf Klatt
ID: 13492388

Thanks for posting the required peaces of code!

While looking at the provided code it looks to me as there isn't another way to refer to the example I've shown you above.

You may think that my answer to your question is "too poor" to accept ... but what I gave you is an example on how to print a table out of a dataset ... you may take that example and shape it to your dataset (DataBank) ... there are certainly more ways ... even thinking about Crystal Reports ... to format a "printing solution" ... sorry, but sitting here and preparing you the "final solution" you're looking for would be something like doing your homework ...

Best regards,

Author Comment

ID: 13492412
I guess I'll just have to live with that and take a look elsewhere,

Thanks for the help though,

LVL 15

Expert Comment

by:Ralf Klatt
ID: 13492653

Having had a second glance at your question "Does anyone have any good links/information on how to format a document for printing within VB.NET?" and being bound to the EE Guidelines ... I respect and accept your comment and also your grading!

I'm sure that if you'll have a second look at the provided code you'll be able to do the coding without someone else doing the work for you!

Best regards,

Author Comment

ID: 13497323

Sorry about the C grade. After another look through the link you gave me, I noticed some information that lead me to the proper answer.

I've asked in community support to get your grade raised.


Featured Post

On Demand Webinar: Networking for the Cloud Era

Did you know SD-WANs can improve network connectivity? Check out this webinar to learn how an SD-WAN simplified, one-click tool can help you migrate and manage data in the cloud.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Although it can be difficult to imagine, someday your child will have a career of his or her own. He or she will likely start a family, buy a home and start having their own children. So, while being a kid is still extremely important, it’s also …
Today, the web development industry is booming, and many people consider it to be their vocation. The question you may be asking yourself is – how do I become a web developer?
Simple Linear Regression
Introduction to Processes

764 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question