I'm not able to update the TextBox
content from another module.
The TextBox
is in a Form called frm_main
and the EventHandler in another module called md_zeiss
.
Init() is called by a button on frm_main
.
Problem:
If I directly call Test() from frm_main
it does change the text.
If called by the event, it does not change the text, but displays the correct MessageBox.
Code:
Module md_zeiss
Sub Init()
Dim fsw As New FileSystemWatcher
fsw.Path = "C:\Output"
fsw.Filter = "*.txt"
fsw.NotifyFilter = NotifyFilters.Attributes Or NotifyFilters.CreationTime Or NotifyFilters.DirectoryName _
Or NotifyFilters.FileName Or NotifyFilters.LastAccess Or NotifyFilters.LastWrite Or NotifyFilters.Security Or NotifyFilters.Size
fsw.EnableRaisingEvents = True
AddHandler fsw.Changed, AddressOf md_zeiss.Main
End Sub
Sub Main(sender As Object, e As IO.FileSystemEventArgs)
Do While IsLocked(e.FullPath) = True
Application.DoEvents()
Loop
Dim fs As New FileStream(e.FullPath, FileMode.Open, FileAccess.Read)
Dim sr As New StreamReader(fs, System.Text.Encoding.Default)
Dim textline As String = vbNullString
Dim nr As String
Dim gi As String
Dim le As String
Do Until sr.Peek = -1
textline = sr.ReadLine
Select Case True
Case InStr(textline, vbTab & "Ø MOLDING_NR_SIDE" & vbTab)
nr = ReadVal(textline, 5)
Case InStr(textline, vbTab & "LENGTH" & vbTab)
gi = ReadVal(textline, 5)
Case InStr(textline, vbTab & "Ø MOLDING_GI_SIDE" & vbTab)
le = ReadVal(textline, 5)
End Select
Loop
Test()
End Sub
Sub Test()
frm_Main.TextBox1.Text = "Test"
MsgBox(frm_Main.TextBox1.Text)
End Sub
The FileSystemWatcher
raises it events on a secondary thread by default. Default instances of forms are thread-specific so if you display the default instance of a form on the UI thread and then try to access the default instance from the handler of a FileSystemWatcher
event (or a method called from that handler) then you're actually referring to two different form objects.
The simplest option is to set the SynchronizingObject
property of the FileSystemWatcher
on the UI thread. You can assign a form or other control to that property and the FileSystemWatcher
will then raise its events on the thread that owns that control, i.e. the UI thread. If you do go down that route, just be sure that your event handler is executed quickly. You don;t want to tie up the UI thread with long-running code, which is why a secondary thread is used by default.
Another option is to use the SynchronizationContext
class in your module to allow you to marshal a method call to the UI thread. You would continue to have the FileSystemWatcher
raise its events on a secondary thread and do the background work there, then call Send
or Post
on the SynchronizationContext
to invoke a method on the UI thread, where using the default instance of that form would refer to the same instance as you have already displayed.
Basically though, the architecture there is bad. You should almost certainly be using a class rather than a module and the form can then keep a reference to an instance of that class. The class could then raise an appropriate event that the form could handle and then the form could update its own TextBox
. If you are access the controls on a form outside that form then the code is inherently bad. Default form instances make doing that easier, which is one reason that seasoned developers generally don't like them. They make it easier for beginners to get up and running, but it also makes it easier for beginners to paint themselves into a corner when things get remotely complex.