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
>> >> >
>> >
>