Search code examples
vb.netprintingpngfilesystemwatcher

printing png file with file system watcher vb.net


I'm trying to print a newly created png file. I'm using File system watcher to react when file is being created and getting path of it.

    Private Sub FileSystemWatcher1_Created(sender As Object, e As FileSystemEventArgs) Handles FileSystemWatcher1.Created
    Dim MyFile As String = e.FullPath.ToString
    Try
        AddHandler PrintDocument1.PrintPage, AddressOf Me.PrintImage
        PrintDocument1.Print()
    Catch ex As Exception
        MsgBox(ex, MsgBoxStyle.Critical, "Error during Print")
    End Try
    End Sub

but when I want to print it I don't know how direct that path to the code from MSDN as with this code Me.PrintImage and Me.PrintImage(MyFile) returns an error

WithEvents PrintDocument1 As New PrintDocument
Private Sub PrintImage(ByVal sender As Object, ByVal ppea As PrintPageEventArgs, MyFile As String)
    ppea.Graphics.DrawImage(Image.FromFile(MyFile), ppea.Graphics.VisibleClipBounds)
    ppea.HasMorePages = False
End Sub

How can i just direct my file to this printing service? code i found was based on static path to the file and was not in the file system watcher and i can't seem to find a way to tie them together. Please help!


Solution

  • Please consider the following:

    • You can't change the signature of a delegate/event like:
    Private Sub PrintImage(ByVal sender As Object, ByVal ppea As PrintPageEventArgs, MyFile As String)
    
    • You always can declare a class members to access them anywhere in the class. You can declare the MyFile like so:
    Public Class Form1
        Private MyFile As String
    End Class
    

    Now you can assign it's value in the FileSystemWatcher1_Created event, and read that value in the PrintImage event. To read more: How to: Control the Scope of a Variable (Visual Basic)

    • You should subscribe to an event just once:
    Public Class Form1
    
        Private MyFile As String
        Private PrintDocument1 As PrintDocument
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            PrintDocument1 = New PrintDocument
            AddHandler PrintDocument1.PrintPage, AddressOf PrintImage
        End Sub
    
        Private Sub PrintImage(sender As Object, e As PrintPageEventArgs)
            '...
        End Sub
    End Class
    

    Or just use the WithEvents and Handles clause the same way you have in the FileSystemWatcher1_Created event.

    Public Class Form1
    
        Private MyFile As String
        Private WithEvents PrintDocument1 As PrintDocument
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            PrintDocument1 = New PrintDocument
        End Sub
    
       Private Sub PrintImage(sender As Object, e As PrintPageEventArgs) Handles PrintDocument1.PrintPage
             '...
        End Sub
    End Class
    

    Or use the designer to add an instance of the PrintDocument component and subscribe to it's events. just like the FileSystemWatcher component.

    Put it all together and you should get something like:

    Public Class Form1
    
        Private MyFile As String
        Private WithEvents PrintDocument1 As PrintDocument
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            PrintDocument1 = New PrintDocument
        End Sub
    
        Private Sub FileSystemWatcher1_Created(sender As Object, e As FileSystemEventArgs) Handles FileSystemWatcher1.Created
            MyFile = e.FullPath
            PrintDocument1.Print()
        End Sub
    
        Private Sub PrintImage(sender As Object, e As PrintPageEventArgs) Handles PrintDocument1.PrintPage
            If Not File.Exists(MyFile) Then
                Return
            End If
    
            Try
                Using bmp = New Bitmap(New MemoryStream(File.ReadAllBytes(MyFile)))
                    e.Graphics.DrawImage(bmp, e.Graphics.VisibleClipBounds)
                End Using
            Catch ex As ArgumentException
                Console.WriteLine("Not Image!")
            Catch ex As Exception
                Console.WriteLine(ex.Message)
            End Try
        End Sub
    
        Protected Overrides Sub OnFormClosed(e As FormClosedEventArgs)
            MyBase.OnFormClosed(e)
    
            PrintDocument1.Dispose()
        End Sub
    End Class
    

    A better approach IMHO is to collect the created files in a list and send them to the printer as one print-job. Useful when - for example - you paste multiple files in the FileSystemWatcher.Path. The FileSystemWatcher.Created event is raised for each file and the PrintDocument.Print method in the preceding code is called for each one as well. We can reduce the print calls to just one to do the same task.

    The code below is a quick Lambda-Expression-Way example.

    Imports System.IO
    Imports System.Windows.Forms
    Imports System.Drawing.Printing
    Imports System.Collections.Generic
    
    Public Class Form1
    
        Private ReadOnly watcher As FileSystemWatcher
        Private ReadOnly timer As Timer 'System.Windows.Forms.Timer
        Private ReadOnly printDoc As PrintDocument
        Private MyFiles As Queue(Of String)
    
        Sub New()
            InitializeComponent()
    
            MyFiles = New Queue(Of String)
    
            watcher = New FileSystemWatcher With {
                .Path = "PathToWatch",
                .EnableRaisingEvents = True
            }
            AddHandler watcher.Created,
                Sub(s, e)
                    If Not MyFiles.Contains(e.FullPath) Then
                        MyFiles.Enqueue(e.FullPath)
                        Invoke(Sub() timer.Start())
                    End If
                End Sub
    
            timer = New Timer With {.Interval = 1000}
            AddHandler timer.Tick,
                Sub(s, e)
                    timer.Stop()
                    printDoc.Print()
                End Sub
    
            printDoc = New PrintDocument
            AddHandler printDoc.PrintPage,
                Sub(s, e)
                    Dim imgFile = MyFiles.Dequeue
                    If Not File.Exists(imgFile) Then
                        Return
                    End If
    
                    Try
                        Using bmp = New Bitmap(New MemoryStream(File.ReadAllBytes(imgFile)))
                            e.Graphics.DrawImage(bmp, e.Graphics.VisibleClipBounds)
                        End Using
                    Catch ex As ArgumentException
                        Console.WriteLine("Not Image!")
                    Catch ex As Exception
                        Console.WriteLine(ex.Message)
                    End Try
    
                    e.HasMorePages = MyFiles.Count > 0
                End Sub
        End Sub
    
        Protected Overrides Sub OnFormClosed(e As FormClosedEventArgs)
            MyBase.OnFormClosed(e)
    
            watcher.Dispose()
            timer.Dispose()
            printDoc.Dispose()
        End Sub
    End Class