Sending data from a thread to my startup form

robplatt

Freshman
Joined
Jul 14, 2006
Messages
39
I've read this post: http://www.xtremedotnettalk.com/showthread.php?t=76924

and have successfully created a thread without using the backgroudnworkerprocess doing this
Code:
    Private Sub Button5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button5.Click
        Dim DBSyncThread As Threading.Thread
        Dim DBSyncThreadStart As New Threading.ThreadStart(AddressOf DBSync)

        DBSyncThread = New Threading.Thread(DBSyncThreadStart)
        DBSyncThread.IsBackground = True
        DBSyncThread.Name = "DBSync"
        DBSyncThread.Start()

    End Sub
    Private Sub DBSync()
        MsgBox("ehasdf boogieman")
        Functions.LogError("boogieman")
    End Sub

the functions.logerror call is a class that takes the passed string and sticks it into a listview on my form then writes that string to a logfile as well.

in the above code the messagebox pops up but the string 'boogieman' never makes it to the list. other areas of my project that arn't threaded use that logerror function very heavily (verbose). i just need to get this thread to be able to write to it too.

I saw on the above url that I needed to use

Dim threadfunction As New MethodInvoker(AddressOf nonthreadfunction)

and in the thread i use Me.BeginInvoke(threadfunction)

but those are sub routines and trying to tie in my function that passes the string just confuses the hell out of me.

please advise.
 
Well.. I Wrote up a similar app to start fresh that looks like this
Code:
Public Class Form1

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        filllist()
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim t As Threading.Thread = New Threading.Thread(AddressOf filllist)
        t.IsBackground = True
        t.Start()

    End Sub
    Private Sub filllist()
        MsgBox("TEst")

        If Me.InvokeRequired = True Then

            Dim test = New Class1

            test.tester("test")

            Dim mi As New MethodInvoker(AddressOf filllist)
            BeginInvoke(mi)

        Else
            Class1.tester("test")
            Dim i As Integer
            For i = 1 To 5000
                ListBox1.Items.Add(i)
            Next
        End If

    End Sub

End Class


Public Class Class1
    Public Shared Function tester(ByVal e As String)
        Form1.ListBox1.Items.Add(e)
        tester = 0
    End Function
End Class

That actually works. So you get my idea. Soemtimes I need to add to a listbox under the normal thread, sometimes i need to add to it under a seperate thread.

I have a feeling I'm not going about the best way, but it does work on THIS sample..

My big program its still not working. It wont fail with an error, but the text never makes it to the control.
 
Nevermind, I spoke too soon, I wasn't paying attention to my own code, if it had worked I would see TWO 'test' in the listbox, im still only seeing the non threaded one.

You get what I need now though. IF you guys can make the above code work. I'd be so greatful.
 
The first call to test.tester isn't being done on the UI Thread, therefore you are encountering the problem the BeginInvoke call is designed to fix.

Also you could have done Class1.tester for both calls to the function rather than creating an instance of Class1.
 
i know. thats what i need to happen. ya i got it figured out how to populate the boxes, but i hav to be able to call that function and pass data to it from one thread to the ui thread.

see. the listbox is a log, very verbose of every action in the program, whats goign on, from what call to where, who clicked what etc. i have to be able to fill it from any thread. i wrote a shared function so that any form could pass data to it. the code above is just a sample. but like you said it wont work. populating the listboxes was easy, you can methodinvoke a sub routine. how do i do it fo ra function?
 
The Form's .Invoke method has an overloaded version that allows you to pass in an array of Parameters to the function itself. I've just tweaked your code so the check fo InvokeRequired is done inside the Class1.tester method rather than the calling method.
The MethodInvoker delegate doesn't allow for parameters / return types so I've also defined a custom delegate for the tester method.
Visual Basic:
Public Class Form1

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        filllist()
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim t As Threading.Thread = New Threading.Thread(AddressOf filllist)
        t.IsBackground = True
        t.Start()

    End Sub
    Private Sub filllist()
       
        Dim i As Integer
        For i = 1 To 5000
            Class1.tester(i.ToString())
        Next
       
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Class1.OutputForm = Me
    End Sub
End Class


Public Class Class1
    Public Delegate Function TesterDelegate(ByVal e As String) As Integer

    Public Shared OutputForm As Form1

    Public Shared Function tester(ByVal e As String) As Integer
        If OutputForm.InvokeRequired Then
            Dim o() As Object = {e}
            Dim mi As New TesterDelegate(AddressOf tester)
            OutputForm.Invoke(mi, o)
        Else
            OutputForm.ListBox1.Items.Add(e)
        End If

        tester = 0
    End Function
End Class

I've changed a couple of other things - the filllist method now calls the .tester method rather than the listbox directly and the Class1 now stores a reference to the output form rather than going through the default instance of Form1.
 
Thats exactly what I needed. Now to just plug it into my main program and hopefully everything goes smooth.

thank you so much.
 
I see only one problem, had i mentioned it earlier maybe it would have saved some time? but this function is called form multiple forms (thats why i put it in a class. except. im learning that more and more functions should probably go in classes, either way), so using outputform = form1, it wont work when form2 calls the same function in the same manner.
 
Will each form log to the same place or to a seperate place? If they are all loging to the same form then as long as the outputform is pointing to the correct form for the logging to be displayed on it shouldn't be a problem.
 
PlausiblyDamp said:
Will each form log to the same place or to a seperate place? If they are all loging to the same form then as long as the outputform is pointing to the correct form for the logging to be displayed on it shouldn't be a problem.

I went ahead and tested my application, and it worked fine. However its not correct. when form2 calls the same function outputform is stil = to form1. if i set class1.outputform = me on form2_load() then that would be correct, but what happens when form1 calls that function again. i could see this being a problem,

what happens if i always use the methodinvoke, regardless if its needed or not.

edit... i see that outputform has to = the form im writing the data to, which is the listview on form1. so this should always work. nevermind my previous rant, im still learning. :)
 
Back
Top