(SOLVED)Simple Multithreaded application(Error)

theodoros2008

Member
Joined
Jun 16, 2008
Messages
5
Programming Experience
1-3
Hello to all!
I have an application that scans for BT devices.When i dont use multithread, the app is freezing while it is scanning and defreeze while not.
I use the following code for MT at Form1_load

VB.NET:
Dim t1 As System.Threading.Thread
        t1 = New Threading.Thread(AddressOf scan_proc)
        t1.Start()

The content of scan_proc is:

VB.NET:
Dim devices As BluetoothDeviceInfo() = btClient.DiscoverDevices(10, True, True, True)



        For i As Integer = 0 To devices.Length - 1

            ListView2.Items.Add(devices(i).DeviceName + "   " + Now)
            DataGridView1.Rows.Insert(0, devices(i).DeviceName, DateTime.Now.ToLongTimeString(), DateTime.Now.ToLongDateString())

        Next
It runs with a timer which call the scan_proc() every x sec.
My problem:When it is scanning for BT devices everything is running good,but when it comes to the point adding the results to the ListView2 i get and InvalidOperationException and the error is (I will translate it from greek since my VB 2008 express is giving me errors in greek,i dont know why)

The operation of the different thread is not valid:There was a access to ListView2 from a different thread that was original created.

Any help?What i am doing wrong?
 
Last edited:
It is a design restriction of Windows that any visual element must only be updated by the thread that created it (because that thread owns the message pump for that control)

What youre doing here is:

a thread starts
it creates your main window and all the controls
it owns them
it then runs the form load
it then hence creates a new thread
two threads exist, one started by the other

the one that was created second, then tries to update controls (labels) owned by the first one. this is not allowed

what the second thread must do is check the control's InvokeRequired property, which compares the thread id of the thread running the code, with the ID of the thread that created the control. If they are DIFFERENT, then InvokeRequired returns true..
..and what you would do there is .Invoke on the control, which will kick the original thread into doing the work, via a delegate (and then you have to mess around passing the data over to the first thread etc)


read MSDN for BackgroundWorker, it is a control that does work in the backrgound and handles all the delegation and invokes necessary to get it to work.

Search this forum, lots is mentioned on BGW.. Youll need to set ReportsProgress to true, handle the necessary event and then, at any iterval you want to report progress, call the ReportProgress(pass_data_in) which will raise the event, and the original thread is used to handle the event.


Comprende? First thread creates BackgroundWorker control, backgroundWorker control does work and when work code tells BackgroundWorker to raise an event announcing progress, it does so. First thread is made to handle the event, so the eventhandling thread is allowed to access the form controls.. SImple :)
 
First of all thank you for the reply.I did do some research on BGW and i finnaly came up to this

1)First the Timer that scan every X second
I have put Timer1.Enable=False and Timer1.Enable=true because i was getting an error that the worker is busy.This one solved this
VB.NET:
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Timer1.Enabled = False
        BackgroundWorker1.RunWorkerAsync()
        Timer1.Enabled = False
    End Sub

2)Then the Dowork
Here as you said i cant control the controls(i.e. the listview) so i only do the "math",the discovery of the devices.
VB.NET:
devices = btClient.DiscoverDevices()
        For i As Integer = 0 To devices.Length - 1
            BackgroundWorker1.ReportProgress(devices(i).DeviceName)
        Next

3)And last i update the control with the above values
VB.NET:
 ListView2.Items.Add(e.ProgressPercentage)

=> which leads me to an conversion name at step 2 that i cant convert string to integer.
I run out of ideas.If i dont found how it works,then i have to force the user not to do anything while scanning.
Any further help is appreciated.
 
The basic problem you have run into now is twofold:

1) Youre not reading the documentation (ReportProgress method -> It's new, you dont know it, RTFM) [while I can accept that your native language isnt English, you *have* to know the difference between a string and an integer in order to be a programmer. You cannot pass a device name as a parameter to a method that is expecting a numerical percentage and then get it out at the other end.
2) Youre coding without thinking. Write some comments, work out the algorithm, then write the code. Remember, weeks of coding can save you hours of planning! :)

Go take a break, have a coffee. Dont think about this for a while
 
Solved!!!!

Went to sleep changed step 2 to
VB.NET:
Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        devices = btClient.DiscoverDevices()

and step 3 to
VB.NET:
Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
        For i As Integer = 0 To devices.Length - 1
            ListView2.Items.Add(devices(i).DeviceName + "     " + Now)
        Next

End Sub

and da da !!1
Hope someone else would benefit!
Thank you cjard,hope you are well and help people by teaching them how to fish(and not give them the fish right away!)
This thread can be cloced:)
VB.NET:
BackgroundWorker1.CancelAsync()
 
Back
Top