Member Avatar for onaclov2000

When I'm attempting to load a program, there is a certain aspect that relies on a separate api to grab information to stick in a listbox (combobox whatever). I would like to be able to load the combobox on a separate thread because that part takes a good 2 minutes, the need for this to be loaded immediately is not there, I can stick a "loading" textbox next to it and when it's done loading change it to loaded, but I can't seem to figure out how to stick it on a separate thread, I tried BG worker but couldn't get it to work.....
I would say that unless you need the data in the combobox for some reason the rest of the program is 100% useable, so I don't want the user to have to wait for a component of the program to load when they may not need it. I hope that makes sense.

Anyone have any suggestions?

Thank you,
onaclov

Recommended Answers

All 6 Replies

if you want to fill a control in a seperate thread then you have to invoke the control or the complete form. else you will get a cross thread exception.
Below an example....

Private Delegate Sub AddItemsDelegate(ByVal newItem As String)

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Dim myThread As New Threading.Thread(AddressOf cmbThread)
        myThread.Start()
    End Sub

    Private Sub cmbThread()
        For i As Integer = 0 To 2000
            Me.Invoke(New AddItemsDelegate(AddressOf addItToBox), "item" & i)
'ComboBox1.Invoke(New AddItemsDelegate(AddressOf addItToBox), "item" & i)
        Next

    End Sub

    Private Sub addItToBox(ByVal newItem As String)
        ComboBox1.Items.Add(newItem)
    End Sub
Member Avatar for onaclov2000

if you want to fill a control in a seperate thread then you have to invoke the control or the complete form. else you will get a cross thread exception.
Below an example....

Private Delegate Sub AddItemsDelegate(ByVal newItem As String)

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Dim myThread As New Threading.Thread(AddressOf cmbThread)
        myThread.Start()
    End Sub

    Private Sub cmbThread()
        For i As Integer = 0 To 2000
            Me.Invoke(New AddItemsDelegate(AddressOf addItToBox), "item" & i)
'ComboBox1.Invoke(New AddItemsDelegate(AddressOf addItToBox), "item" & i)
        Next

    End Sub

    Private Sub addItToBox(ByVal newItem As String)
        ComboBox1.Items.Add(newItem)
    End Sub

so if I call invoke is that calling the "current" running instance? I'm not sure if I'm following why you get the cross thread error, I do recall getting that, but I'm not sure how the thread that has the actual form on it is related to the one that you would "invoke".

Sorry Maybe some links to stuff to read up on it might help if it's too much of a pain to explain.

Thank you,

Member Avatar for onaclov2000

So I tried reading a little, I'm still having some problems:

An error occurred creating the form. See Exception.InnerException for details. The error is: Current thread must be set to single thread apartment (STA) mode before OLE calls can be made. Ensure that your Main function has STAThreadAttribute marked on it.


Not really sure where to go with that....I looked it up on google, and most of the 'responses' were "ohhh I found a dll that needed to be rebuild (because <STAThread()> _, didn't seem to work)

Public Class frmMain
<STAThread()> _
    Private Sub FrmMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim Tasks As New Stuff

Dim myThread As New Threading.Thread(AddressOf Tasks.getSome)

        myThread.Start()
End Sub

End Class


Public Class Stuff
Private Delegate Sub AddItemsDelegate(ByVal newItem As String)
    Private Delegate Sub EnableBox()

Public Sub getSome()
       
        Dim i As Integer
        Dim location As Integer
        Dim someCounter as Integer
        Dim someText as Integer
        someText = "hey"

        For i = 1 To someCounter                 
          frmMain.ViewList.Invoke(New AddItemsDelegate(AddressOf addItToBox), someText & i)
        Next
        location = frmMain.ViewList.FindString("hey")
        frmMain.Invoke(New EnableBox(AddressOf enable))
    End Sub


    <STAThread()> _
    Private Sub addItToBox(ByVal newItem As String)

        frmMain.ViewList.Items.Add(newItem)

    End Sub
    <STAThread()> _
    Private Sub selectedIndex(ByVal num As Integer)

        frmMain.ViewList.SelectedIndex = num

    End Sub
    <STAThread()> _
    Private Sub enable()

        frmMain.ViewList.Enabled = True

    End Sub

End Class

I think I'm just really confused. I thought I was getting it, basically I call a thread to start on it's own, then use an "invoke" to call a "local" function that isn't multithreaded, and pass it an argument, and that local function adds it (since It's part of the control it can handle things), I also tried getting fancy and enabling the combobox, I just tried that without the first part being ran (so in theory it should only enable the combobox). I get the same error,

I thought MAYBE I needed to make the combobox STA, so I tried adding that to it as well....but no luck..


Let me know if you have any other ideas.

I have tested the code you posted and got no error messages. Anyway your code didn't work if i use frmMain.Viewlist so i assigned this control as parameter (Byval sender as Object) and hand it over to the class.
Hope this helps

Public Class frmMain

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Dim Tasks As New Stuff
        Dim myThread As New Threading.Thread(AddressOf Tasks.getSome)
        myThread.Start(ViewList)
    End Sub
End Class



Friend Class Stuff

    Private Delegate Sub AddItemsDelegate(ByVal newItem As String)
    Private cntrl As ComboBox

    Friend Sub getSome(ByVal sender As Object)
        While frmMain.ViewList.Handle = Nothing Or frmMain.Handle = Nothing
            Threading.Thread.Sleep(10) 'wait till frmMain and Viewlist is created, else you might get an exception
        End While

        cntrl = DirectCast(sender, ComboBox) 'assign the frmMain.Viewlist to cntrl

        Dim i As Integer
        Dim location As Integer
        Dim someCounter As Integer = 2000
        Dim someText As String = "hey"

        For i = 1 To someCounter
            cntrl.Invoke(New AddItemsDelegate(AddressOf addItToBox), someText & i)
        Next
        location = cntrl.FindString("hey")
        cntrl.Invoke(New MethodInvoker(AddressOf enable)) 'use the standard MethodInvoker if there are no parameters needed
    End Sub


    Private Sub addItToBox(ByVal newItem As String)
        cntrl.Items.Add(newItem)
    End Sub

    Private Sub selectedIndex(ByVal num As Integer)
        cntrl.SelectedIndex = num
    End Sub

    Private Sub enable()
        cntrl.Enabled = True
    End Sub

End Class
commented: Great Help +2
Member Avatar for onaclov2000

I have tested the code you posted and got no error messages. Anyway your code didn't work if i use frmMain.Viewlist so i assigned this control as parameter (Byval sender as Object) and hand it over to the class.
Hope this helps

Public Class frmMain

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Dim Tasks As New Stuff
        Dim myThread As New Threading.Thread(AddressOf Tasks.getSome)
        myThread.Start(ViewList)
    End Sub
End Class



Friend Class Stuff

    Private Delegate Sub AddItemsDelegate(ByVal newItem As String)
    Private cntrl As ComboBox

    Friend Sub getSome(ByVal sender As Object)
        While frmMain.ViewList.Handle = Nothing Or frmMain.Handle = Nothing
            Threading.Thread.Sleep(10) 'wait till frmMain and Viewlist is created, else you might get an exception
        End While

        cntrl = DirectCast(sender, ComboBox) 'assign the frmMain.Viewlist to cntrl

        Dim i As Integer
        Dim location As Integer
        Dim someCounter As Integer = 2000
        Dim someText As String = "hey"

        For i = 1 To someCounter
            cntrl.Invoke(New AddItemsDelegate(AddressOf addItToBox), someText & i)
        Next
        location = cntrl.FindString("hey")
        cntrl.Invoke(New MethodInvoker(AddressOf enable)) 'use the standard MethodInvoker if there are no parameters needed
    End Sub


    Private Sub addItToBox(ByVal newItem As String)
        cntrl.Items.Add(newItem)
    End Sub

    Private Sub selectedIndex(ByVal num As Integer)
        cntrl.SelectedIndex = num
    End Sub

    Private Sub enable()
        cntrl.Enabled = True
    End Sub

End Class

I haven't had time to play with it much for a while (and might not for a bit again),
"For now" I just used BG worker and passed back the results through the e, and then in the "work done" (can't remember the name) I actually populated the list, still not quite what I was wanting to do, and your way might make it work...I'll have to look at it when I get a chance....Thank you for all the help so far!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.