Search code examples
vb.netfilesystemwatcherchecklistbox

VB.NET Updating UI and controls in real time


I am trying to make a CheckedListBox_Notifications that shows items listing the changes happening in a specific directory. Upon the load of the form I have the code:

    Public Watcher_ActiveProjects As New FileSystemWatcher()

    Sub Form_Home_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        'Watcher_ActiveProjects
        Watcher_ActiveProjects = New FileSystemWatcher() With {
        .Path = Directory_ActiveProjects,
        .IncludeSubdirectories = True,
        .NotifyFilter = NotifyFilters.FileName Or NotifyFilters.DirectoryName Or NotifyFilters.LastWrite,
        .EnableRaisingEvents = True
    }

        AddHandler Watcher_ActiveProjects.Created, AddressOf oncreate
    end sub

And so upon "OnCreate" I am adding the item using the code:

    Public Sub oncreate(sender As Object, e As FileSystemEventArgs)

        'Set Variables
        strFullPath = e.FullPath
        strProjectSuffix = Split(strFullPath, "\")(3)

        Form_Home.CheckedListBox_Notifications.Items.Add("File created:")

    End Sub

The problem is that using OnCreate sub it doesn't update the CheckedListBox_Notifications. I hear that it might be related to threading? Could someone, please, help me with this one?


Solution

  • A FileSystemWatcher raises its events on a background thread by default. You are using the default instance of Form_Home in your event handler and default instances are thread-specific. That means that your code is working properly but it is populating a control on a different form that you can't see, rather than the one you're looking at.

    There are various ways you could address this but, in your case, the simplest option is to set the SynchronizingObject property of the FileSystemWatcher - just assign the current form, i.e. Me - and then the events will be raised on the UI thread. You can then access controls on the current form directly.

    I would also recommend that you simplify your code by declaring your field WithEvents and then use Handles rather than AddHandler.

    Private WithEvents activeProjectsWatcher As New FileSystemWatcher With {
            .Path = Directory_ActiveProjects,
            .IncludeSubdirectories = True,
            .NotifyFilter = NotifyFilters.FileName Or NotifyFilters.DirectoryName Or NotifyFilters.LastWrite,
            .EnableRaisingEvents = True,
            .SynchronizingObject = Me
        }
    
    Private Sub ActiveProjectsWatcher_Created(sender As Object, e As EventArgs) Handles ActiveProjectsWatcher.Created
        '...
    
        CheckedListBox_Notifications.Items.Add("File created:")
    End Sub
    

    Having said that, if you are doing some long-running work other than what you've shown us, it would be more appropriate to do that on a background thread and then only do the UI update on the UI thread.