Updating Form Controls from Separate Worker Thread - Must all code be in the same source file?

  • Thread starter Thread starter snaga.ohme
  • Start date Start date
S

snaga.ohme

I have a small problem that's keeping my up late....very late...

It's the standard updating the controls on a windows form from a
separate worker thread problem.

I create a simple form in VB with a Start button (to start the worker
thread) and a single label control

A simple update procedure makes the changes to the label control, i.e.
changes the label text to some value. a delegate to this procedure is
invoked on the UI thread by the worker thread when it's time to
update.

Everything works if all my code is in the form source file, i.e.
Form1.vb., in which case the update procedure is invoked as follows:

me.invoke(updateDelegate)

If I move the code for the worker thread to a separate source file
and contain it within a module (module1.vb), i.e.,

public Module Module1

public sub MyThread()

.....code

' invoke update delegate
Form1.invoke(updateDelegate)

end sub

end module

And then invoke the update delegate but now referencing the UI thread
with Form1.invoke(...) versus me.invoke(...) it will not work.

I get the following error:

Invoke or BeginInvoke cannot be called on a control until the window
handle has been created.

Is there a requirement that everything be in the same source file?
 
All code does not need to be in the same source file, but you will need
to have access to an instance of the form in question in your MyThread
sub.
 
All code does not need to be in the same source file, but you will need
to have access to an instance of the form in question in your MyThread
sub.

--
Bryan Phillips
MCT, MCSD, MCDBA, MCSE
Blog: http://bphillips76.spaces.live.com
Web Site: http://www.composablesystems.net

That's what I thought...I guess for some reason I'm not grabbing the
right instance. There is only one form...here is the code that works
and doesn't - maybe you can spot my mistake. Code below is for a
single form with one text box and one button. Worker Thread simply
updates the text in the text box. Since I see a form pop up on the
screen I don't understand why I get the exception that I do....

++++++++++++++++++++ THIS WORKS +++++++++++++++++++++++++++++++++++++
+ All code in one file, Form1.vbs
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
imports System.threading

Public Class Form1

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e
As System.EventArgs) Handles Button1.Click
Dim t As New Thread(AddressOf MyThread)
t.Start()
End Sub

Public Delegate Sub UpdateDelegate(ByVal msg As String)

Public Sub UpdateTextBox(ByVal msg As String)
TextBox1.Text = msg
End Sub

Public Sub MyThread()
' Call the delegate to update the label text
Dim updateDelegate As New UpdateDelegate(AddressOf
UpdateTextBox)
Me.Invoke(updateDelegate, "Test")

End Sub

Private Sub TextBox1_TextChanged(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles TextBox1.TextChanged

End Sub
End Class

++++++++++++++++++++++++++ THIS WILL NOT WORK++++++++++++++++++++++++++
+++++++++++++++++++++
+ code in files form1.vbs and module1.vbs
+
+ hitting the text button throws exception in line
"Form1.Invoke(updateDelegate, "Test")
+ "Invoke or BeginInvoke cannot be called on a control until the
window handle has been created."
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++
[Form1.vbs]
-------------------------
imports System.threading

Public Class Form1

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e
As System.EventArgs) Handles Button1.Click
Dim t As New Thread(AddressOf MyThread)
t.Start()
End Sub


Private Sub TextBox1_TextChanged(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles TextBox1.TextChanged

End Sub
End Class

[module1.vbs]
--------------------
Module Module1

Public Delegate Sub UpdateDelegate(ByVal msg As String)

Public Sub UpdateTextBox(ByVal msg As String)
Form1.TextBox1.Text = msg
End Sub

Public Sub MyThread()
' Call the delegate to update the label text
Dim updateDelegate As New UpdateDelegate(AddressOf
UpdateTextBox)
Form1.Invoke(updateDelegate, "Test")

End Sub
End Module
 
You need to pass the instance of Form1 to the two functions which will
look like this:

Form1.vb
---------------------

....

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Dim t As New Thread(AddressOf MyThread)
t.Start(Me) ' <- Pass the instance of Form1 to the MyThread
subroutine.
End Sub

....

Module1.vb
---------------------

....

Public Delegate Sub UpdateDelegate(ByVal msg As String, ByVal f As
Form1)

Public Sub UpdateTextBox(ByVal msg As String, ByVal f As Form1)
f.TextBox1.Text = msg
End Sub

Public Sub MyThread(ByVal data As Object) ' <- This is the signature for
a ParameterizedThreadStart delegate.
' Convert data to a Form1 object.
Dim f As Form1 = CType(data, Form1)

' Call the delegate to update the label text
Dim updateDelegate As New UpdateDelegate(AddressOf UpdateTextBox)

f.Invoke(updateDelegate, "Test", f) ' <- Here we are passing the Form1
instance again.

End Sub

....

I hope this helps.


--
Bryan Phillips
MCT, MCSD, MCDBA, MCSE
Blog: http://bphillips76.spaces.live.com
Web Site: http://www.composablesystems.net



All code does not need to be in the same source file, but you will need
to have access to an instance of the form in question in your MyThread
sub.

--
Bryan Phillips
MCT, MCSD, MCDBA, MCSE
Blog: http://bphillips76.spaces.live.com
Web Site: http://www.composablesystems.net

That's what I thought...I guess for some reason I'm not grabbing the
right instance. There is only one form...here is the code that works
and doesn't - maybe you can spot my mistake. Code below is for a
single form with one text box and one button. Worker Thread simply
updates the text in the text box. Since I see a form pop up on the
screen I don't understand why I get the exception that I do....

++++++++++++++++++++ THIS WORKS +++++++++++++++++++++++++++++++++++++
+ All code in one file, Form1.vbs
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
imports System.threading

Public Class Form1

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e
As System.EventArgs) Handles Button1.Click
Dim t As New Thread(AddressOf MyThread)
t.Start()
End Sub

Public Delegate Sub UpdateDelegate(ByVal msg As String)

Public Sub UpdateTextBox(ByVal msg As String)
TextBox1.Text = msg
End Sub

Public Sub MyThread()
' Call the delegate to update the label text
Dim updateDelegate As New UpdateDelegate(AddressOf
UpdateTextBox)
Me.Invoke(updateDelegate, "Test")

End Sub

Private Sub TextBox1_TextChanged(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles TextBox1.TextChanged

End Sub
End Class

++++++++++++++++++++++++++ THIS WILL NOT WORK++++++++++++++++++++++++++
+++++++++++++++++++++
+ code in files form1.vbs and module1.vbs
+
+ hitting the text button throws exception in line
"Form1.Invoke(updateDelegate, "Test")
+ "Invoke or BeginInvoke cannot be called on a control until the
window handle has been created."
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++
[Form1.vbs]
-------------------------
imports System.threading

Public Class Form1

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e
As System.EventArgs) Handles Button1.Click
Dim t As New Thread(AddressOf MyThread)
t.Start()
End Sub


Private Sub TextBox1_TextChanged(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles TextBox1.TextChanged

End Sub
End Class

[module1.vbs]
--------------------
Module Module1

Public Delegate Sub UpdateDelegate(ByVal msg As String)

Public Sub UpdateTextBox(ByVal msg As String)
Form1.TextBox1.Text = msg
End Sub

Public Sub MyThread()
' Call the delegate to update the label text
Dim updateDelegate As New UpdateDelegate(AddressOf
UpdateTextBox)
Form1.Invoke(updateDelegate, "Test")

End Sub
End Module
 
Back
Top