Control not updating from cross thread call?

Senoska

Member
Joined
Jun 27, 2006
Messages
15
Programming Experience
Beginner
Hello everyone.

First off, I hope this is in the right section. Sorry if its not.

I have a few classes. One of the classes handles everything to do with updating controls (Such as adding items to a listview, etc.) and another is handling loops. I'm trying to add something to a richtextbox from another thread. This is my code

in ClsControls:
VB.NET:
    Public Sub doLog(ByVal rtbLog As RichTextBox, ByVal what As String, Optional ByVal clr As String = "black", Optional ByVal indent As Integer = 0, Optional ByVal timestamp As Boolean = True)
        'Check if the control needs an invoke
        If rtbLog.InvokeRequired Then : Dim deleg As New delDoLog(AddressOf doLog) : rtbLog.Invoke(deleg, rtbLog, what, clr, indent, timestamp) : Exit Sub : End If


        'Set up variables
        Dim Time, strAppend As String
        Dim color As Color = color.FromName(clr)

        'Set up message
        Time = "[" & DateTime.Now.ToShortTimeString & "] : "
        If timestamp Then : strAppend = Time & what & vbNewLine : Else : strAppend = what & vbNewLine : End If

        'Build output
        With rtbLog
            .SelectionColor = color
            .SelectionIndent = indent
            .AppendText(strAppend)
            .ScrollToCaret()
        End With

    End Sub

Loop class:
VB.NET:
    Public Sub startThread(ByVal strUri As String, ByVal strFldr As String, ByVal tmr As String, ByVal threadDilim As String)
        Dim threadName As String
        Dim mainThread As Thread = New Thread(AddressOf getPageLoop) 'Create a new Thread
        threadName = strUri & threadDilim & strFldr & threadDilim & tmr 'Set up the variable to be passed to the thread
        mainThread.Name = threadName 'Pass the info to the thread via the name
        mainThread.Start() 'Start the thread
    End Sub

    Public Sub getPageLoop()
        Dim try3 As New clsControls
        try3.doLog(My.Forms.frmMain.rtbLog, "Being called form thread")
    End Sub

I have it set up like this just to see if it works, which obviously, it doesn't. If I put both pieces of code on the main form, however, it works without a problem.

The code executes fine. If I add a breakpoint, everything works how its supposed too, however, the textbox isnt updating.

eg:
29et0cy.jpg


But with no change to the text box.

Whats going on? Any ideas?
 
Textbox is updating, but you're not seeing it because you are not displaying that form. Default forms are thread specific, so My.Forms.frmMain called from secondary thread returns a new default form instance for that thread, and not the actual main of your application. You need to find a way to pass the correct control reference to the secondary thread.
 
hi Senoska,

the correct way to pass stuff across different threads is using Invoke (google it), but honestly I've never used because the background workers provide a easy straight forward way of doing it with the ProgressChanged and RunWorkerCompleted methods. I say you should try it.
 
Just incase anyone (For what ever reason) ever runs into this problem, this is how I solved it.

Added this to frmMain:
VB.NET:
    Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'Set the control array up
        setControls()

        'Sent message to log saying the program started okay
        cntrls.doLog(rtbLog, "Started up.", "green")
    End Sub

Private Sub setControls()
        'This sub is to add the controls to an arraylist. This is a ghetto fix to accessing controls from another thread. Works, but ghetto
        Dim tmpStruct As New clsControls.frmControls
        With tmpStruct : .imgRealtime = imgRealtime : .lstDownloads = lstDownloads : .lstThreads = lstThreads : .rtbLog = rtbLog : End With
        cntrls.arrControls.Add(tmpStruct)
    End Sub

    Private Sub btnStartStop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStartStop.Click
        doBot.setClasses(cntrls, dtaHndle)
        doBot.startAllScan(dtaHndle)
    End Sub

Added this to the Controls class:
VB.NET:
    'Frustrated fix to threading problem.
    Public arrControls As New ArrayList

    Public Structure frmControls
        Dim rtbLog As RichTextBox
        Dim imgRealtime As PictureBox
        Dim lstThreads As ListView
        Dim lstDownloads As ListView
    End Structure

To the MainLoop class:
VB.NET:
    Dim controls As clsControls
    Dim datahandler As Datahandler
    Dim threadDilim As String = ""

    Public Sub setClasses(ByVal cntrls As clsControls, ByVal datahandle As Datahandler)
        'Import all the classes used in the main form into the class
        controls = cntrls : datahandler = datahandle : threadDilim = datahandle.threadDilim
    End Sub

It works.
 
Back
Top