Hello Daniweb, and thank you for taking the time to read this post.

I have a question of efficiency.

I am wondering, what is the most efficient way to print from a listview. The listview's values are loaded from a database, and I would like to print from that listview. So far I have tried moving them to a text file and printing the text file, but Windows said that "The file is to large for notpad" even though I was not using notepad.

Is it advised to create an array of structures and then load everything into the array?
If so, do I create the array dynamicly?

Please, if anyone has any suggestions, let me know.

Thank you,
begginnerdev

Recommended Answers

All 11 Replies

Wow, that gives me a good reference point. Thank you so much.

Unfortunately, it will not convert from the previous version to Visual Studio 2010. I can't get into the file to view the code either. :'( Thank you for the help though.

.NET provide a flexible way to organize your data and print by using PrintDocument. The following is the "Hello World" example of using PrintDocument.

Dim WithEvents pd As New System.Drawing.Printing.PrintDocument

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        pd.Print()
    End Sub

    Private Sub pd_PrintPage(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles pd.PrintPage
        e.Graphics.DrawString("Hello World", Me.Font, Brushes.Black, 0, 0)
    End Sub
Member Avatar for Unhnd_Exception

An example of printing a listview in details view.

Prints the columns to the current size as on the screen and prints images in the image list if one exists.

Public Class Form1

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        'Junk items for demonstation.
        For i = 1 To 100
            ListView1.Items.Add(New ListViewItem(New String() {"Dani", "Web", "Is", "Awesome"}, 0))
        Next

    End Sub


    Private Sub ButtonPrintListView_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonPrintListView.Click
        'Used printPreviewDialog instead of printdialog
        'to save paper while debugging.  When finished
        'swith out to PrintDialog.
        Dim PrintPreview As New PrintPreviewDialog
        PrintPreview.Document = PrintDocument1
        PrintPreview.ShowDialog()
    End Sub

    Private Sub PrintDocument1_PrintPage(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
        'The below is desined for details view.
        If ListView1.View = View.Details Then
            PrintDetails(e)
        End If
    End Sub

    Private Sub PrintDetails(ByRef e As System.Drawing.Printing.PrintPageEventArgs)
        Static LastIndex As Integer = 0
        Static CurrentPage As Integer = 0

        'Getting the current dpi so the textleftpad 
        'will be the same on a different dpi than 
        'the 96 i'm using.  Won't make much of a difference though.
        Dim DpiGraphics As Graphics = Me.CreateGraphics
        Dim DpiX As Integer = DpiGraphics.DpiX
        Dim DpiY As Integer = DpiGraphics.DpiY

        DpiGraphics.Dispose()

        Dim X, Y As Integer
        Dim ImageWidth As Integer
        Dim TextRect As Rectangle = Rectangle.Empty
        Dim TextLeftPad As Single = CSng(4 * (DpiX / 96)) '4 pixel pad on the left.
        Dim ColumnHeaderHeight As Single = CSng(ListView1.Font.Height + (10 * (DpiX / 96))) '5 pixel pad on the top an bottom
        Dim StringFormat As New StringFormat
        Dim PageNumberWidth As Single = e.Graphics.MeasureString(CStr(CurrentPage), ListView1.Font).Width

        'Specify the text should be drawn in the center of the line and
        'that the text should not be wrapped and the text should show
        'ellipsis would cut off.
        StringFormat.FormatFlags = StringFormatFlags.NoWrap
        StringFormat.Trimming = StringTrimming.EllipsisCharacter
        StringFormat.LineAlignment = StringAlignment.Center

        CurrentPage += 1

        'Start the x and  y at the top left margin.
        X = CInt(e.MarginBounds.X)
        Y = CInt(e.MarginBounds.Y)

        'Draw the column headers
        For ColumnIndex As Integer = 0 To ListView1.Columns.Count - 1
            TextRect.X = X
            TextRect.Y = Y
            TextRect.Width = ListView1.Columns(ColumnIndex).Width
            TextRect.Height = ColumnHeaderHeight

            e.Graphics.FillRectangle(Brushes.LightGray, TextRect)
            e.Graphics.DrawRectangle(Pens.DarkGray, TextRect)

            'TextLeftPad adds a little padding from the gridline.
            'Add it to the left and subtract it from the right.
            TextRect.X += TextLeftPad
            TextRect.Width -= TextLeftPad
            e.Graphics.DrawString(ListView1.Columns(ColumnIndex).Text, ListView1.Font, Brushes.Black, TextRect, StringFormat)

            'Move the x position over the width of the column width.
            'Since I subtracted some padding add the padding back
            'when offsetting.
            X += TextRect.Width + TextLeftPad
        Next

        'Just drew the headers.  Move the Y down the height
        'of the column headers.
        Y += ColumnHeaderHeight

        'Now draw the items.  If this is the first page then the 
        'last index will be zero.  If its not then the last index
        'will be the last index we tried to draw but had no room.
        For i = LastIndex To ListView1.Items.Count - 1

            With ListView1.Items(i)
                'Start the x at the pages left margin.
                X = CInt(e.MarginBounds.X)

                'Check for Last Line
                If Y + .Bounds.Height > e.MarginBounds.Bottom Then
                    'This item won't fit.
                    'subtract 1 from i so the next time this sub
                    'is entered we can start with this item.
                    LastIndex = i - 1
                    e.HasMorePages = True
                    StringFormat.Dispose()

                    'Draw the current page number before leaving.
                    e.Graphics.DrawString(CStr(CurrentPage), ListView1.Font, Brushes.Black, (e.PageBounds.Width - PageNumberWidth) / 2, e.PageBounds.Bottom - ListView1.Font.Height * 2)
                    Exit Sub
                End If

                'Print Images.
                'The image width is used so we can draw the gridline
                'around the image about to be drawn.  You'll see it 
                'below.
                ImageWidth = 0
                If ListView1.SmallImageList IsNot Nothing Then
                    'If the image key is set then draw the image
                    'with the key .  If not draw the image with the
                    'index.  A tiny bit of validation would be good.
                    If Not String.IsNullOrEmpty(.ImageKey) Then
                        e.Graphics.DrawImage(ListView1.SmallImageList.Images(.ImageKey), X, Y)
                    ElseIf .ImageIndex >= 0 Then
                        e.Graphics.DrawImage(ListView1.SmallImageList.Images(.ImageIndex), X, Y)
                    End If

                    ImageWidth = ListView1.SmallImageList.ImageSize.Width
                End If


                'Now draw the subitems.  using the columns count so the 
                'grid lines can be drawn.  If used the subitems count then
                'the table would not be full if some subitems where less
                'than others.
                For ColumnIndex As Integer = 0 To ListView1.Columns.Count - 1

                    TextRect.X = X
                    TextRect.Y = Y
                    TextRect.Width = ListView1.Columns(ColumnIndex).Width
                    TextRect.Height = .Bounds.Height

                    If ListView1.GridLines Then
                        e.Graphics.DrawRectangle(Pens.DarkGray, TextRect)
                    End If

                    'If an image is drawn then shift over the x to 
                    'accomadate its width. If this was shifted before
                    'now then the gridline with draw rect above would be
                    ' on the wrong side of the image.
                    If ColumnIndex = 0 Then TextRect.X += ImageWidth

                    'Add a little padding from the gridline.
                    TextRect.X += TextLeftPad
                    TextRect.Width -= TextLeftPad

                    If ColumnIndex < .SubItems.Count Then
                        'This item has at least the same number of
                        'subitems as the current column index.
                        e.Graphics.DrawString(.SubItems(ColumnIndex).Text, ListView1.Font, Brushes.Black, TextRect, StringFormat)
                    End If

                    'Shift the x of the width of this subitem.
                    'Add some padding to the left side of the text
                    'so need to add it back.
                    X += TextRect.Width + TextLeftPad
                Next

                'Set the next line
                Y += .Bounds.Height

            End With
        Next

        'Draw the final page number.
        e.Graphics.DrawString(CStr(CurrentPage), ListView1.Font, Brushes.Black, (e.PageBounds.Width - PageNumberWidth) / 2, e.PageBounds.Bottom - ListView1.Font.Height * 2)

        StringFormat.Dispose()
        LastIndex = 0
        CurrentPage = 0
    End Sub

End Class
commented: For a long post ^_^. Probably waste a hour of your life doing it. +9

Thank everyone for there help, and I am sorry for the slow reply.

thanks for this article.. it helps me.. but can help me how to adjust the listview item to another place? it places on the top of paper.. i want to place in middle of page. :) thanx.

I modified your code now is in color

        'Keep track of the Line Y postition to determine if there are more pages

        Static CurrentYPosition As Integer = 0

        'The below is desined for details view.
        If ListView1.View = View.Details Then
            PrintDetails(e)
        End If
    End Sub
    Private Sub PrintDetails(ByRef e As System.Drawing.Printing.PrintPageEventArgs)
        If ListView1.Visible = True Then
            Static LastIndex As Integer = 0
            Static CurrentPage As Integer = 0
            'Getting the current dpi so the textleftpad
            'will be the same on a different dpi than
            'the 96 i'm using. Won't make much of a difference though.
            Dim DpiGraphics As Graphics = Me.CreateGraphics
            Dim DpiX As Integer = DpiGraphics.DpiX
            Dim DpiY As Integer = DpiGraphics.DpiY
            DpiGraphics.Dispose()
            Dim X, Y As Integer
            Dim ImageWidth As Integer
            Dim TextRect As Rectangle = Rectangle.Empty
            Dim TextLeftPad As Single = CSng(4 * (DpiX / 96)) '4 pixel pad on the left.
            Dim ColumnHeaderHeight As Single = CSng(ListView1.Font.Height + (10 * (DpiX / 96))) '5 pixel pad on the top an bottom
            Dim StringFormat As New StringFormat
            Dim PageNumberWidth As Single = e.Graphics.MeasureString(CStr(CurrentPage), ListView1.Font).Width
            'Specify the text should be drawn in the center of the line and
            'that the text should not be wrapped and the text should show
            'ellipsis would cut off.
            StringFormat.FormatFlags = StringFormatFlags.NoWrap
            StringFormat.Trimming = StringTrimming.EllipsisCharacter
            StringFormat.LineAlignment = StringAlignment.Center
            CurrentPage += 1
            'Start the x and y at the top left margin.
            X = CInt(e.MarginBounds.X)
            Y = CInt(e.MarginBounds.Y)
            'Draw the column headers
            For ColumnIndex As Integer = 0 To ListView1.Columns.Count - 1
                TextRect.X = X
                TextRect.Y = Y
                TextRect.Width = ListView1.Columns(ColumnIndex).Width
                TextRect.Height = ColumnHeaderHeight
                e.Graphics.FillRectangle(Brushes.LightGray, TextRect)
                e.Graphics.DrawRectangle(Pens.DarkGray, TextRect)
                'TextLeftPad adds a little padding from the gridline.
                'Add it to the left and subtract it from the right.
                TextRect.X += TextLeftPad
                TextRect.Width -= TextLeftPad
                e.Graphics.DrawString(ListView1.Columns(ColumnIndex).Text, ListView1.Font, Brushes.Black, TextRect, StringFormat)
                'Move the x position over the width of the column width.
                'Since I subtracted some padding add the padding back
                'when offsetting.
                X += TextRect.Width + TextLeftPad
            Next
            'Just drew the headers. Move the Y down the height
            'of the column headers.
            Y += ColumnHeaderHeight
            'Now draw the items. If this is the first page then the
            'last index will be zero. If its not then the last index
            'will be the last index we tried to draw but had no room.
            For i = LastIndex To ListView1.Items.Count - 1

                With ListView1.Items(i)
                    'Start the x at the pages left margin.
                    X = CInt(e.MarginBounds.X)
                    'Check for Last Line
                    If Y + .Bounds.Height > e.MarginBounds.Bottom Then
                        'This item won't fit.
                        'subtract 1 from i so the next time this sub
                        'is entered we can start with this item.
                        LastIndex = i - 1
                        e.HasMorePages = True
                        StringFormat.Dispose()
                        'Draw the current page number before leaving.

                        e.Graphics.DrawString(CStr(CurrentPage), ListView1.Font, Brushes.Black, (e.PageBounds.Width - PageNumberWidth) / 2, e.PageBounds.Bottom - ListView1.Font.Height * 2)
                        Exit Sub
                    End If
                    'Print Images.
                    'The image width is used so we can draw the gridline
                    'around the image about to be drawn. You'll see it
                    'below.
                    ImageWidth = 0
                    If ListView1.SmallImageList IsNot Nothing Then
                        'If the image key is set then draw the image
                        'with the key . If not draw the image with the
                        'index. A tiny bit of validation would be good.
                        If Not String.IsNullOrEmpty(.ImageKey) Then
                            e.Graphics.DrawImage(ListView1.SmallImageList.Images(.ImageKey), X, Y)
                        ElseIf .ImageIndex >= 0 Then
                            e.Graphics.DrawImage(ListView1.SmallImageList.Images(.ImageIndex), X, Y)
                        End If
                        ImageWidth = ListView1.SmallImageList.ImageSize.Width
                    End If
                    'Now draw the subitems. using the columns count so the
                    'grid lines can be drawn. If used the subitems count then
                    'the table would not be full if some subitems where less
                    'than others.
                    For ColumnIndex As Integer = 0 To ListView1.Columns.Count - 1
                        TextRect.X = X
                        TextRect.Y = Y
                        TextRect.Width = ListView1.Columns(ColumnIndex).Width
                        TextRect.Height = .Bounds.Height
                        Dim bColor As Integer = ListView1.Items(i).BackColor.ToArgb
                        Dim myBColor As Color = ColorTranslator.FromHtml(bColor)
                        e.Graphics.FillRectangle(New SolidBrush(myBColor), TextRect)
                        If ListView1.GridLines Then
                            e.Graphics.DrawRectangle(Pens.DarkGray, TextRect)
                        End If
                        'If an image is drawn then shift over the x to
                        'accomadate its width. If this was shifted before
                        'now then the gridline with draw rect above would be
                        ' on the wrong side of the image.
                        If ColumnIndex = 0 Then TextRect.X += ImageWidth
                        'Add a little padding from the gridline.
                        TextRect.X += TextLeftPad
                        TextRect.Width -= TextLeftPad
                        If ColumnIndex < .SubItems.Count Then
                            'This item has at least the same number of
                            'subitems as the current column index.
                            Dim TColor As Integer = ListView1.Items(i).SubItems(ColumnIndex).ForeColor.ToArgb
                            Dim myTColor As Color = ColorTranslator.FromHtml(TColor)
                            e.Graphics.DrawString(.SubItems(ColumnIndex).Text, ListView1.Font, New SolidBrush(myTColor), TextRect, StringFormat)
                        End If
                        'Shift the x of the width of this subitem.
                        'Add some padding to the left side of the text
                        'so need to add it back.
                        X += TextRect.Width + TextLeftPad
                    Next
                    'Set the next line
                    Y += .Bounds.Height
                End With

            Next
            'Draw the final page number.
            e.Graphics.DrawString(CStr(CurrentPage), ListView1.Font, Brushes.Black, (e.PageBounds.Width - PageNumberWidth) / 2, e.PageBounds.Bottom - ListView1.Font.Height * 2)
            StringFormat.Dispose()
            LastIndex = 0
            CurrentPage = 0

        End If

    End Sub

Thanks for the code. I have a problem, my listview can't fit to the printpreview. Can you help?

How i add a title header in your sample printlistview?

I have the same question as pride123, Im not able too center the listview cant fit on the printpreview.

is there anyway to do that?

Thanks for your help.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.