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.
Related Article: Need help converting to C#
is a VB.NET discussion thread by lxXTaCoXxl that has 4 replies and was last updated 1 year ago.
Ancient Dragon
Achieved Level 70
32,145 posts since Aug 2005
Reputation Points: 5,836
Solved Threads: 2,577
Skill Endorsements: 69
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.
Reverend Jim
Carpe per diem
3,612 posts since Aug 2010
Reputation Points: 563
Solved Threads: 451
Skill Endorsements: 32
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"})
Else
Form1.TextBox1.Text = "fred"
End If
End Sub
End Class
Edit: The reference methods shown above assume that you have the "Application Framework" enabled.
TnTinMN
Practically a Master Poster
640 posts since Jun 2012
Reputation Points: 418
Solved Threads: 148
Skill Endorsements: 13
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:
form1.TextBox1.Text="Hello"
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.Invoke(Sub()
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
TurnOn()
frm = Me
End Sub
Private Shared Sub OnChanged(source As Object, e As FileSystemEventArgs)
frm.TextBox1.Invoke(Sub()
frm.TextBox1.AppendText(e.FullPath & vbCrLf)
End Sub)
End Sub
__avd
Posting Genius (adatapost)
8,736 posts since Oct 2008
Reputation Points: 2,141
Solved Threads: 1,262
Skill Endorsements: 50
In VB.Net (with explicit type) the syntax would be
Dim reftext As TextBox = Me.Controls("TextBox1")
Reverend Jim
Carpe per diem
3,612 posts since Aug 2010
Reputation Points: 563
Solved Threads: 451
Skill Endorsements: 32