1.11M Members

How to write to instance of a TextBox from shared function


I'm trying to write a simple program that detects when files are changed in a folder (for another question here). It has a standard Windows with a TextBox and a couple buttons. Upon program start it calls .NET function FileSystemWatcher then sets up four event handlers for it. What I want is for the event handlers to write something to the TextBox, but VB.NET complains that shared functions can't access instance objects. I know a work-around in c++ by setting a global pointer to the instance which can be accessed by shared functions but can't think of a work around in VB. Anyone know how to do this?

The error is on line 30 of the code posted below.

Private Sub TurnOn()
        watcher = New FileSystemWatcher()
        ' Create a new FileSystemWatcher and set its properties. 
        watcher.Path = txtFolder.Text
        ' Watch for changes in LastAccess and LastWrite times, and 
        ' the renaming of files or directories. 
        watcher.NotifyFilter = (NotifyFilters.LastAccess Or NotifyFilters.LastWrite Or NotifyFilters.FileName Or NotifyFilters.DirectoryName)
        ' watch all files.
        watcher.Filter = "*.*"

        ' Add event handlers. 
        AddHandler watcher.Changed, AddressOf OnChanged
        AddHandler watcher.Created, AddressOf OnChanged
        AddHandler watcher.Deleted, AddressOf OnChanged
        AddHandler watcher.Renamed, AddressOf OnRenamed

        ' Begin watching.
        watcher.EnableRaisingEvents = True

        ' Wait for the user to quit the program.
        'Console.WriteLine("Press 'q' to quit the sample.")
        'While Chr(Console.Read()) <> "q"c
        'End While
        'Return True
        btnOnOff.Text = "OFF"
    End Sub

    Private Shared Sub OnChanged(source As Object, e As FileSystemEventArgs)
        ' Specify what is done when a file is changed, created, or deleted.
        txtFolder.Text = txtFolder.Text + "File: " & e.FullPath & " " & e.ChangeType '<<<< error on this line
    End Sub

The error message is
error BC30369: Cannot refer to an instance member of a class from within a shared method or shared member initializer without an explicit instance of the class.


If you check out my code snippet BackgroundWorker IP Monitor it shows how to use Delegates to access the textbox from another thread. I think that is what you will have to do.


Other than the obvious, drop the "Shared" keyword, you can use any of the reference syntaxes to the form shown below.

Jim is correct that you will bump into cross thread issues with the FileSystemWatcher events, so I include an example of that technique as well.

Public Class Form1

   'create a delegate template for the method
   Delegate Sub dummy(ByVal caller As TextBox, ByVal text As String)

   ' a method that matches the template defined above
   Sub settext(ByVal caller As TextBox, ByVal text As String)
      caller.Text = text
   End Sub

   Private Shared Sub test()
      My.Forms.Form1.TextBox1.Text = "wilma"
      CType(My.Application.OpenForms.Item("Form1"), Form1).TextBox1.Text = "barney"

      ' Since you are handling events, these events my arrive on a thread other than the UI thread.
      ' To prevent a cross thread error, check if an Invoke is needed
      If Form1.TextBox1.InvokeRequired Then
         ' invoke a call on the UI thread
         Form1.TextBox1.Invoke(New dummy(AddressOf Form1.settext), New Object() {Form1.TextBox1, "dino"})
         Form1.TextBox1.Text = "fred"
      End If
   End Sub

End Class

Edit: The reference methods shown above assume that you have the "Application Framework" enabled.


In VB.NET, we can use className (i.e. name of Form class - eg Form1.Text) to access the instance members from within the static methods or other forms/classes. And we use Me keyword if we want to use members of FORM from within the instance methods of current form.

So the we can access controls and their properties via:


However, you can't use this methods (above mentioned) to access/change the controls properties outside the UI thread(into the handlers). You need to call Control.Invoke or Control.BeginInvoke method so that way you can update UI from secondary thread.

So I'd like to suggest two solutions:

Workaround First : Make that handler non-static (non-shared)

Private Sub OnChanged(source As Object, e As FileSystemEventArgs)
                            TextBox1.AppendText(e.FullPath & vbCrLf)
                        End Sub)
End Sub

Workaround second : For static event handler, declare shared form reference variable,

Shared frm As Form1
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    frm = Me
End Sub
Private Shared Sub OnChanged(source As Object, e As FileSystemEventArgs)
                            frm.TextBox1.AppendText(e.FullPath & vbCrLf)
                        End Sub)
End Sub

In VB.Net (with explicit type) the syntax would be

Dim reftext As TextBox = Me.Controls("TextBox1")
Isn't it about time forums rewarded their contributors?

Earn rewards points for helping others. Gain kudos. Cash out. Get better answers yourself.

It's as simple as contributing editorial or replying to discussions labeled or OP Kudos

This article has been dead for over six months: Start a new discussion instead
Start New Discussion
Tags Related to this Article