Hello! I'm trying to update a text box from a thread. It works fine
until my thread is created from a seperate class. To illustrate, here's
my form code (the textbox is txtOutput.text) and for the class:

(This all works fine if the "Count" class is declared simply as a
function within form1 - but outside of that the control updates are
invisible!

Imports System.Threading
Delegate Sub SetTextCallback(ByVal [text] As String)
Public Class Form1
Dim tClass As count
Dim t As Thread
Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e
As System.EventArgs) Handles btnStart.Click
tClass = New count
t = New Thread(AddressOf tClass.bProcess)
t.Start()
While t.IsAlive
Thread.Sleep(20)
End While
End Sub

Public Sub SetText(ByVal [text] As String)
' InvokeRequired required compares the thread ID of the
' calling thread to the thread ID of the creating thread.
' If these threads are different, it returns true.
If Me.txtOutput.InvokeRequired Then
Dim d As New SetTextCallback(AddressOf SetText)
Me.Invoke(d, New Object() {[text]})
Else
Me.txtOutput.Text = [text] & txtOutput.Text
Me.txtOutput.Refresh()
End If
End Sub

Private Sub btnAbort_Click(ByVal sender As System.Object, ByVal e
As System.EventArgs) Handles btnAbort.Click
t.Abort()
End Sub
End Class

And here's the class for the count class:

Public Class count
Inherits Form1
Public i As Integer

Sub New()
i = 0
End Sub
Sub bProcess()
For i = 1 To 1000
'If i Mod 25 = 0 Then
' SetText(i.ToString & " " & ControlChars.CrLf)
' 'txtOutput.Text = i.ToString & " " & ControlChars.CrLf
'Else
SetText(i.ToString & " ")
'End If
Next
End Sub
End Class

Re: Control (textbox) update from thread invisible by Henning

Henning
Mon Jan 08 10:56:37 CST 2007

Hello,

UI updated are only possible from the thread which created the UI control...

The solution for your problem here is to call the Invoke method from the
Form or Textbox where the form resides and update the Textbox via a
delegate.

Best regards,
Henning Krause

<brett.mack@gmail.com> wrote in message
news:1168273287.420933.130940@42g2000cwt.googlegroups.com...
> Hello! I'm trying to update a text box from a thread. It works fine
> until my thread is created from a seperate class. To illustrate, here's
> my form code (the textbox is txtOutput.text) and for the class:
>
> (This all works fine if the "Count" class is declared simply as a
> function within form1 - but outside of that the control updates are
> invisible!
>
> Imports System.Threading
> Delegate Sub SetTextCallback(ByVal [text] As String)
> Public Class Form1
> Dim tClass As count
> Dim t As Thread
> Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e
> As System.EventArgs) Handles btnStart.Click
> tClass = New count
> t = New Thread(AddressOf tClass.bProcess)
> t.Start()
> While t.IsAlive
> Thread.Sleep(20)
> End While
> End Sub
>
> Public Sub SetText(ByVal [text] As String)
> ' InvokeRequired required compares the thread ID of the
> ' calling thread to the thread ID of the creating thread.
> ' If these threads are different, it returns true.
> If Me.txtOutput.InvokeRequired Then
> Dim d As New SetTextCallback(AddressOf SetText)
> Me.Invoke(d, New Object() {[text]})
> Else
> Me.txtOutput.Text = [text] & txtOutput.Text
> Me.txtOutput.Refresh()
> End If
> End Sub
>
> Private Sub btnAbort_Click(ByVal sender As System.Object, ByVal e
> As System.EventArgs) Handles btnAbort.Click
> t.Abort()
> End Sub
> End Class
>
> And here's the class for the count class:
>
> Public Class count
> Inherits Form1
> Public i As Integer
>
> Sub New()
> i = 0
> End Sub
> Sub bProcess()
> For i = 1 To 1000
> 'If i Mod 25 = 0 Then
> ' SetText(i.ToString & " " & ControlChars.CrLf)
> ' 'txtOutput.Text = i.ToString & " " & ControlChars.CrLf
> 'Else
> SetText(i.ToString & " ")
> 'End If
> Next
> End Sub
> End Class
>


Re: Control (textbox) update from thread invisible by brett

brett
Mon Jan 08 11:17:20 CST 2007

Yes, but how do I do that?

Henning Krause [MVP - Exchange] wrote:
> Hello,
>
> UI updated are only possible from the thread which created the UI control...
>
> The solution for your problem here is to call the Invoke method from the
> Form or Textbox where the form resides and update the Textbox via a
> delegate.
>
> Best regards,
> Henning Krause
>
> <brett.mack@gmail.com> wrote in message
> news:1168273287.420933.130940@42g2000cwt.googlegroups.com...
> > Hello! I'm trying to update a text box from a thread. It works fine
> > until my thread is created from a seperate class. To illustrate, here's
> > my form code (the textbox is txtOutput.text) and for the class:
> >
> > (This all works fine if the "Count" class is declared simply as a
> > function within form1 - but outside of that the control updates are
> > invisible!
> >
> > Imports System.Threading
> > Delegate Sub SetTextCallback(ByVal [text] As String)
> > Public Class Form1
> > Dim tClass As count
> > Dim t As Thread
> > Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e
> > As System.EventArgs) Handles btnStart.Click
> > tClass = New count
> > t = New Thread(AddressOf tClass.bProcess)
> > t.Start()
> > While t.IsAlive
> > Thread.Sleep(20)
> > End While
> > End Sub
> >
> > Public Sub SetText(ByVal [text] As String)
> > ' InvokeRequired required compares the thread ID of the
> > ' calling thread to the thread ID of the creating thread.
> > ' If these threads are different, it returns true.
> > If Me.txtOutput.InvokeRequired Then
> > Dim d As New SetTextCallback(AddressOf SetText)
> > Me.Invoke(d, New Object() {[text]})
> > Else
> > Me.txtOutput.Text = [text] & txtOutput.Text
> > Me.txtOutput.Refresh()
> > End If
> > End Sub
> >
> > Private Sub btnAbort_Click(ByVal sender As System.Object, ByVal e
> > As System.EventArgs) Handles btnAbort.Click
> > t.Abort()
> > End Sub
> > End Class
> >
> > And here's the class for the count class:
> >
> > Public Class count
> > Inherits Form1
> > Public i As Integer
> >
> > Sub New()
> > i = 0
> > End Sub
> > Sub bProcess()
> > For i = 1 To 1000
> > 'If i Mod 25 = 0 Then
> > ' SetText(i.ToString & " " & ControlChars.CrLf)
> > ' 'txtOutput.Text = i.ToString & " " & ControlChars.CrLf
> > 'Else
> > SetText(i.ToString & " ")
> > 'End If
> > Next
> > End Sub
> > End Class
> >


Re: Control (textbox) update from thread invisible by Henning

Henning
Mon Jan 08 12:14:35 CST 2007

Hell,

looking at your code...

>> > While t.IsAlive
>> > Thread.Sleep(20)
>> > End While

This effectively block your Message queue on your window from being
processed....

And I don't understand why you do this...

Best regards,
Henning Krause

why do you
<brett.mack@gmail.com> wrote in message
news:1168276639.920032.39750@i15g2000cwa.googlegroups.com...
> Yes, but how do I do that?
>
> Henning Krause [MVP - Exchange] wrote:
>> Hello,
>>
>> UI updated are only possible from the thread which created the UI
>> control...
>>
>> The solution for your problem here is to call the Invoke method from the
>> Form or Textbox where the form resides and update the Textbox via a
>> delegate.
>>
>> Best regards,
>> Henning Krause
>>
>> <brett.mack@gmail.com> wrote in message
>> news:1168273287.420933.130940@42g2000cwt.googlegroups.com...
>> > Hello! I'm trying to update a text box from a thread. It works fine
>> > until my thread is created from a seperate class. To illustrate, here's
>> > my form code (the textbox is txtOutput.text) and for the class:
>> >
>> > (This all works fine if the "Count" class is declared simply as a
>> > function within form1 - but outside of that the control updates are
>> > invisible!
>> >
>> > Imports System.Threading
>> > Delegate Sub SetTextCallback(ByVal [text] As String)
>> > Public Class Form1
>> > Dim tClass As count
>> > Dim t As Thread
>> > Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e
>> > As System.EventArgs) Handles btnStart.Click
>> > tClass = New count
>> > t = New Thread(AddressOf tClass.bProcess)
>> > t.Start()
>> > While t.IsAlive
>> > Thread.Sleep(20)
>> > End While
>> > End Sub
>> >
>> > Public Sub SetText(ByVal [text] As String)
>> > ' InvokeRequired required compares the thread ID of the
>> > ' calling thread to the thread ID of the creating thread.
>> > ' If these threads are different, it returns true.
>> > If Me.txtOutput.InvokeRequired Then
>> > Dim d As New SetTextCallback(AddressOf SetText)
>> > Me.Invoke(d, New Object() {[text]})
>> > Else
>> > Me.txtOutput.Text = [text] & txtOutput.Text
>> > Me.txtOutput.Refresh()
>> > End If
>> > End Sub
>> >
>> > Private Sub btnAbort_Click(ByVal sender As System.Object, ByVal e
>> > As System.EventArgs) Handles btnAbort.Click
>> > t.Abort()
>> > End Sub
>> > End Class
>> >
>> > And here's the class for the count class:
>> >
>> > Public Class count
>> > Inherits Form1
>> > Public i As Integer
>> >
>> > Sub New()
>> > i = 0
>> > End Sub
>> > Sub bProcess()
>> > For i = 1 To 1000
>> > 'If i Mod 25 = 0 Then
>> > ' SetText(i.ToString & " " & ControlChars.CrLf)
>> > ' 'txtOutput.Text = i.ToString & " " & ControlChars.CrLf
>> > 'Else
>> > SetText(i.ToString & " ")
>> > 'End If
>> > Next
>> > End Sub
>> > End Class
>> >
>


Re: Control (textbox) update from thread invisible by brett

brett
Tue Jan 09 07:49:07 CST 2007

I was assuming that if I didn't do this, the main thread would just
suck all of the processor iterating through the while loop; I guess now
that isn't correct? Sorry, I've been teaching myself on the fly, no
formal programming education (I'm sure it shows)!
The below code works.

Question: On the main form code "SetText" routine, should I uncomment
the Monitor.Enter(me) & Monitor.Exit(me) when I have more than one
background thread running at the same time, updating the textbox?

What I've done so far is this. Main form code follows:
Imports System.Threading
Public Delegate Sub SetTextCallback(ByVal [text] As String)

Public Class Form1
Dim tClass As count
Dim t As Thread
Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e
As System.EventArgs) Handles btnStart.Click
btnStart.Enabled = False
tClass = New count
t = New Thread(AddressOf tClass.bProcess)
t.Start()
btnStart.Enabled = True
End Sub
Public Sub SetText(ByVal [text] As String)
' InvokeRequired required compares the thread ID of the
' calling thread to the thread ID of the creating thread.
' If these threads are different, it returns true.
'Monitor.Enter(Me)
If Me.txtOutput.InvokeRequired Then
Dim d As New SetTextCallback(AddressOf SetText)
Me.Invoke(d, New Object() {[text]})
Else
Me.txtOutput.Text = [text] & txtOutput.Text
Me.txtOutput.Refresh()
End If
'Monitor.Exit(Me)
End Sub
Private Sub btnAbort_Click(ByVal sender As System.Object, ByVal e
As System.EventArgs) Handles btnAbort.Click
t.Abort()
End Sub

End Class

And in the "Count" class code, I've put this:

Imports system.threading

Public Class count
Public i As Integer
Dim f1 As Form1
Dim st As SetTextCallback
Sub New()
i = 0
st = New SetTextCallback(AddressOf Form1.SetText)
End Sub
Sub bProcess()
For i = 1 To 1000
st(i.ToString & " ")
Thread.Sleep(10)
Next
End Sub
End Class

Henning Krause [MVP - Exchange] wrote:
> Hell,
>
> looking at your code...
>
> >> > While t.IsAlive
> >> > Thread.Sleep(20)
> >> > End While
>
> This effectively block your Message queue on your window from being
> processed....
>
> And I don't understand why you do this...
>
> Best regards,
> Henning Krause
>
> why do you
> <brett.mack@gmail.com> wrote in message
> news:1168276639.920032.39750@i15g2000cwa.googlegroups.com...
> > Yes, but how do I do that?
> >
> > Henning Krause [MVP - Exchange] wrote:
> >> Hello,
> >>
> >> UI updated are only possible from the thread which created the UI
> >> control...
> >>
> >> The solution for your problem here is to call the Invoke method from the
> >> Form or Textbox where the form resides and update the Textbox via a
> >> delegate.
> >>
> >> Best regards,
> >> Henning Krause
> >>
> >> <brett.mack@gmail.com> wrote in message
> >> news:1168273287.420933.130940@42g2000cwt.googlegroups.com...
> >> > Hello! I'm trying to update a text box from a thread. It works fine
> >> > until my thread is created from a seperate class. To illustrate, here's
> >> > my form code (the textbox is txtOutput.text) and for the class:
> >> >
> >> > (This all works fine if the "Count" class is declared simply as a
> >> > function within form1 - but outside of that the control updates are
> >> > invisible!
> >> >
> >> > Imports System.Threading
> >> > Delegate Sub SetTextCallback(ByVal [text] As String)
> >> > Public Class Form1
> >> > Dim tClass As count
> >> > Dim t As Thread
> >> > Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e
> >> > As System.EventArgs) Handles btnStart.Click
> >> > tClass = New count
> >> > t = New Thread(AddressOf tClass.bProcess)
> >> > t.Start()
> >> > While t.IsAlive
> >> > Thread.Sleep(20)
> >> > End While
> >> > End Sub
> >> >
> >> > Public Sub SetText(ByVal [text] As String)
> >> > ' InvokeRequired required compares the thread ID of the
> >> > ' calling thread to the thread ID of the creating thread.
> >> > ' If these threads are different, it returns true.
> >> > If Me.txtOutput.InvokeRequired Then
> >> > Dim d As New SetTextCallback(AddressOf SetText)
> >> > Me.Invoke(d, New Object() {[text]})
> >> > Else
> >> > Me.txtOutput.Text = [text] & txtOutput.Text
> >> > Me.txtOutput.Refresh()
> >> > End If
> >> > End Sub
> >> >
> >> > Private Sub btnAbort_Click(ByVal sender As System.Object, ByVal e
> >> > As System.EventArgs) Handles btnAbort.Click
> >> > t.Abort()
> >> > End Sub
> >> > End Class
> >> >
> >> > And here's the class for the count class:
> >> >
> >> > Public Class count
> >> > Inherits Form1
> >> > Public i As Integer
> >> >
> >> > Sub New()
> >> > i = 0
> >> > End Sub
> >> > Sub bProcess()
> >> > For i = 1 To 1000
> >> > 'If i Mod 25 = 0 Then
> >> > ' SetText(i.ToString & " " & ControlChars.CrLf)
> >> > ' 'txtOutput.Text = i.ToString & " " & ControlChars.CrLf
> >> > 'Else
> >> > SetText(i.ToString & " ")
> >> > 'End If
> >> > Next
> >> > End Sub
> >> > End Class
> >> >
> >


Re: Control (textbox) update from thread invisible by Henning

Henning
Tue Jan 09 08:39:26 CST 2007

Hello,

I would assume that setting a text value is not a thread safe operaiton, so
using a Monitor here is ok. But you should use the SyncLock keyword in
Visual Basic, as it will wrap the Monitor.Exit in a finally block.

Best regards,
Henning Krause


<brett.mack@gmail.com> wrote in message
news:1168350547.724654.28410@s34g2000cwa.googlegroups.com...
>I was assuming that if I didn't do this, the main thread would just
> suck all of the processor iterating through the while loop; I guess now
> that isn't correct? Sorry, I've been teaching myself on the fly, no
> formal programming education (I'm sure it shows)!
> The below code works.
>
> Question: On the main form code "SetText" routine, should I uncomment
> the Monitor.Enter(me) & Monitor.Exit(me) when I have more than one
> background thread running at the same time, updating the textbox?
>
> What I've done so far is this. Main form code follows:
> Imports System.Threading
> Public Delegate Sub SetTextCallback(ByVal [text] As String)
>
> Public Class Form1
> Dim tClass As count
> Dim t As Thread
> Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e
> As System.EventArgs) Handles btnStart.Click
> btnStart.Enabled = False
> tClass = New count
> t = New Thread(AddressOf tClass.bProcess)
> t.Start()
> btnStart.Enabled = True
> End Sub
> Public Sub SetText(ByVal [text] As String)
> ' InvokeRequired required compares the thread ID of the
> ' calling thread to the thread ID of the creating thread.
> ' If these threads are different, it returns true.
> 'Monitor.Enter(Me)
> If Me.txtOutput.InvokeRequired Then
> Dim d As New SetTextCallback(AddressOf SetText)
> Me.Invoke(d, New Object() {[text]})
> Else
> Me.txtOutput.Text = [text] & txtOutput.Text
> Me.txtOutput.Refresh()
> End If
> 'Monitor.Exit(Me)
> End Sub
> Private Sub btnAbort_Click(ByVal sender As System.Object, ByVal e
> As System.EventArgs) Handles btnAbort.Click
> t.Abort()
> End Sub
>
> End Class
>
> And in the "Count" class code, I've put this:
>
> Imports system.threading
>
> Public Class count
> Public i As Integer
> Dim f1 As Form1
> Dim st As SetTextCallback
> Sub New()
> i = 0
> st = New SetTextCallback(AddressOf Form1.SetText)
> End Sub
> Sub bProcess()
> For i = 1 To 1000
> st(i.ToString & " ")
> Thread.Sleep(10)
> Next
> End Sub
> End Class
>
> Henning Krause [MVP - Exchange] wrote:
>> Hell,
>>
>> looking at your code...
>>
>> >> > While t.IsAlive
>> >> > Thread.Sleep(20)
>> >> > End While
>>
>> This effectively block your Message queue on your window from being
>> processed....
>>
>> And I don't understand why you do this...
>>
>> Best regards,
>> Henning Krause
>>
>> why do you
>> <brett.mack@gmail.com> wrote in message
>> news:1168276639.920032.39750@i15g2000cwa.googlegroups.com...
>> > Yes, but how do I do that?
>> >
>> > Henning Krause [MVP - Exchange] wrote:
>> >> Hello,
>> >>
>> >> UI updated are only possible from the thread which created the UI
>> >> control...
>> >>
>> >> The solution for your problem here is to call the Invoke method from
>> >> the
>> >> Form or Textbox where the form resides and update the Textbox via a
>> >> delegate.
>> >>
>> >> Best regards,
>> >> Henning Krause
>> >>
>> >> <brett.mack@gmail.com> wrote in message
>> >> news:1168273287.420933.130940@42g2000cwt.googlegroups.com...
>> >> > Hello! I'm trying to update a text box from a thread. It works fine
>> >> > until my thread is created from a seperate class. To illustrate,
>> >> > here's
>> >> > my form code (the textbox is txtOutput.text) and for the class:
>> >> >
>> >> > (This all works fine if the "Count" class is declared simply as a
>> >> > function within form1 - but outside of that the control updates are
>> >> > invisible!
>> >> >
>> >> > Imports System.Threading
>> >> > Delegate Sub SetTextCallback(ByVal [text] As String)
>> >> > Public Class Form1
>> >> > Dim tClass As count
>> >> > Dim t As Thread
>> >> > Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e
>> >> > As System.EventArgs) Handles btnStart.Click
>> >> > tClass = New count
>> >> > t = New Thread(AddressOf tClass.bProcess)
>> >> > t.Start()
>> >> > While t.IsAlive
>> >> > Thread.Sleep(20)
>> >> > End While
>> >> > End Sub
>> >> >
>> >> > Public Sub SetText(ByVal [text] As String)
>> >> > ' InvokeRequired required compares the thread ID of the
>> >> > ' calling thread to the thread ID of the creating thread.
>> >> > ' If these threads are different, it returns true.
>> >> > If Me.txtOutput.InvokeRequired Then
>> >> > Dim d As New SetTextCallback(AddressOf SetText)
>> >> > Me.Invoke(d, New Object() {[text]})
>> >> > Else
>> >> > Me.txtOutput.Text = [text] & txtOutput.Text
>> >> > Me.txtOutput.Refresh()
>> >> > End If
>> >> > End Sub
>> >> >
>> >> > Private Sub btnAbort_Click(ByVal sender As System.Object, ByVal e
>> >> > As System.EventArgs) Handles btnAbort.Click
>> >> > t.Abort()
>> >> > End Sub
>> >> > End Class
>> >> >
>> >> > And here's the class for the count class:
>> >> >
>> >> > Public Class count
>> >> > Inherits Form1
>> >> > Public i As Integer
>> >> >
>> >> > Sub New()
>> >> > i = 0
>> >> > End Sub
>> >> > Sub bProcess()
>> >> > For i = 1 To 1000
>> >> > 'If i Mod 25 = 0 Then
>> >> > ' SetText(i.ToString & " " & ControlChars.CrLf)
>> >> > ' 'txtOutput.Text = i.ToString & " " &
>> >> > ControlChars.CrLf
>> >> > 'Else
>> >> > SetText(i.ToString & " ")
>> >> > 'End If
>> >> > Next
>> >> > End Sub
>> >> > End Class
>> >> >
>> >
>


Re: Control (textbox) update from thread invisible by lasse

lasse
Wed Jan 10 06:51:17 CST 2007

brett.mack@gmail.com wrote:
> I was assuming that if I didn't do this, the main thread would just
> suck all of the processor iterating through the while loop; I guess now
> that isn't correct? Sorry, I've been teaching myself on the fly, no
> formal programming education (I'm sure it shows)!
> The below code works.
>
> Question: On the main form code "SetText" routine, should I uncomment
> the Monitor.Enter(me) & Monitor.Exit(me) when I have more than one
> background thread running at the same time, updating the textbox?
<snip>
>>>>> Public Sub SetText(ByVal [text] As String)
>>>>> ' InvokeRequired required compares the thread ID of the
>>>>> ' calling thread to the thread ID of the creating thread.
>>>>> ' If these threads are different, it returns true.
>>>>> If Me.txtOutput.InvokeRequired Then
>>>>> Dim d As New SetTextCallback(AddressOf SetText)
>>>>> Me.Invoke(d, New Object() {[text]})
>>>>> Else
>>>>> Me.txtOutput.Text = [text] & txtOutput.Text
>>>>> Me.txtOutput.Refresh()
>>>>> End If
>>>>> End Sub
<snip>

You do not need the monitor for this method, the way it is above is
fine. Messages to the main thread are processed one at a time.

--
Lasse Vågsæther Karlsen
mailto:lasse@vkarlsen.no