?
Solved

Thread Safe Calls

Posted on 2006-10-19
11
Medium Priority
?
815 Views
Last Modified: 2008-03-06
I have a progress bar set to marquee on an mdi parent status bar. To make it run smoothly and continuously while updating I thought it may be time to try somehting new rather than Application.DoEvents.

So I have a procedure in a child form which is called by the following

           ....enable the progress bar

            Dim newthread As New Threading.Thread(AddressOf MyProcedure)
            newthread.Start()

         
The procedure fills a datatable from various tables, then a DataView which is sorted, which is then used to populate a DataGridView control. I have found out that (via debug message) I have to check the DataGridView.InvokeRequired property when i try to set the DataGridView datasource, and then do something else if the answer is True, when doing something to a control not invoked by the same thread. I am not sure what code I need if the answer is true.

so..

    Private Sub MyProcedure()


        ....do some stuff

         If MyDataGridView.InvokeRequired Then

            ......WHAT GOES HERE

          else

             MyDataGridView.DataSource = MyDataView

        End If

        'Disable progress bar
        me.cursor = cursors.default
        MyMdiParent.ProgressBar.Enabled=false
       

PS. I have also discovered i will get the same problem when i try to reset the cursor for the form back to default and also try to disable the progress bar as they were set on different threads

End Sub

I am assuming of course this is the way to go for smoothly operating progress bars
0
Comment
Question by:JeffvClayton
  • 5
  • 3
  • 3
11 Comments
 
LVL 8

Assisted Solution

by:doraiswamy
doraiswamy earned 300 total points
ID: 17765485
Interesting as I was tinkering with a progress bar in a separate thread myself earlier today.
However, I'm not sure what exactly you are looking for. Do you want the progress bar in the background, marquee-ing smoothly? Then that should be in the separate thread.

Something like this:
Dim newthread As New Threading.Thread(AddressOf MyProcedure)
            newthread.Start()

   ' Do whatever you have to do
  '
   newthread.abort()     ' kill it


Private sub MyProcedure()
            Dim p As New ProgressBar
            p.Maximum = 10
            p.Minimum = 1
            Dim waitform As New Form
            waitform.Text = "Doing Something... Wait"
            waitform.MinimizeBox = False
            waitform.MaximizeBox = False
            waitform.Controls.Add(p)
            p.Left = (waitform.Width - p.Width) / 2
            p.Top = (waitform.Height - p.Height) / 2
            p.Visible = True
            waitform.Show()
            While True
                Thread.Sleep(250)   ' will update the progress bar every 250 milli seconds
                If p.Value = p.Maximum Then
                    p.Value = p.Minimum
                Else
                    p.Value += 1
                End If
            End While

        End Sub


0
 
LVL 3

Author Comment

by:JeffvClayton
ID: 17765572
Yes i do you want the progress bar in the background, marquee-ing smoothly, but I do not want to create a new form, i have a progress bar in a status strip at the bottom of an Mdi parent which is in the original thread, I want to use that. Does it mean i basically have to add the progress bar to the status strip at runtime? Or can i manage the invokerequired properties as suggested by microsoft?
0
 
LVL 8

Expert Comment

by:doraiswamy
ID: 17765873
I'm not sure about the "invokerequired" property. You can try creating a progress bar at runtime and accessing it from the thread.
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 3

Author Comment

by:JeffvClayton
ID: 17765995
OK, that is something to try.

I have also tried this as the last line in the procedure with no error messages, but no data in the DataGridView either!

 MyDataGridView.Invoke(MyDataGridView.DataSource, MyDataView.ToTable)
0
 
LVL 8

Expert Comment

by:doraiswamy
ID: 17766196
Sorry, in the earlier post I meant create a progress bar at design time, not runtime
0
 
LVL 9

Accepted Solution

by:
DjDezmond earned 1200 total points
ID: 17766334
You need to supply a delegate sub, kind of like a template that your code passes through. You then invoke through that delegate. If you have parameters that you need to pass, the delegate sub contains those same params. The delegate sub is only one line...

----------------------------------------------
Delegate Sub InvokeToControl(AnyParam1 as Type, AnyParam2 as Type)
----------------------------------------------

Then specify the sub routine that holds your code...

----------------------------------------------
Sub YourSub(AnyParam1 as Type, AnyParam2 as Type)
'Do whatever needs doing
End sub
----------------------------------------------

Now...

----------------------------------------------
If MyDataGridView.InvokeRequired Then
MyDataGridView.Invoke(New InvokeToControl(AddressOf YourSub), New Object() {AnyParam1, AnyParam2})
Else
YourSub(AnyParam1, AnyParam2)
----------------------------------------------

In this example i have specified 2 paramaters, obviously adjust as you need to, but if you have none, then the invoke line just becomes:

MyDataGridView.Invoke(New InvokeToControl(AddressOf YourSub))

Hope this helps

Dez

0
 
LVL 3

Author Comment

by:JeffvClayton
ID: 17766392
I have solved the problem, you cant change an object from a different thread, you need all this....


Instead of   'MyDataGridView.DataSource = MyDataView' as the last line of the procedure in the new thread

                              you need a new procedure call as the last line e.g.   PassNewDataView(MyDataView.ToTable)

                                                                                                         End Sub
                               'Another sub which runs in the new thread
                             '--------------------------------------------------
                                Sub PassNewDataView(ByVal MyDataView As DataTable)
                                          Me.BeginInvoke(New DelegateUpdateSource(AddressOf Me.ChangeSource), New Object() {MyDataView})
                               End Sub

                              ' then a new Delegate Sub as this....
                               ' ----------------------------------------
                               Public Delegate Sub DelegateUpdateSource(ByVal DV As DataTable)


  'Finally a sub which runs in the original thread to change the datasource and stop the progress bar                                  
   '-----------------------------------------------------------------------------------------------------------------

    Sub ChangeSource(ByVal DV As DataTable)

        Me.MyDataGridView.DataSource = DV

        Me.Cursor = Cursors.Default
         MParent.PB1.Enabled = False
     

    End Sub

Thanks anyway

Jeff
0
 
LVL 3

Author Comment

by:JeffvClayton
ID: 17766405
Thanks Dez, I was typing as you sent the message.
0
 
LVL 9

Expert Comment

by:DjDezmond
ID: 17766554
I would of typed it a hell of a lot sooner (just as you posted the msg) but i was on my phone the whole time! Sorry mate!

Glad its working now anyway.

Cheers,

Dez
0
 
LVL 9

Expert Comment

by:DjDezmond
ID: 17766577
one more thing...

                               Sub PassNewDataView(ByVal MyDataView As DataTable)
                                          Me.BeginInvoke(New DelegateUpdateSource(AddressOf Me.ChangeSource), New Object() {MyDataView})
                               End Sub

There is no need for a seperate sub here... you can just call:

Me.BeginInvoke(New DelegateUpdateSource(AddressOf Me.ChangeSource), New Object() {MyDataView})

... from anywhere on the thread

Cheers,
Dez
0
 
LVL 3

Author Comment

by:JeffvClayton
ID: 17766595
Even Better!

Thanks Dez.
0

Featured Post

Upgrade your Question Security!

Add Premium security features to your question to ensure its privacy or anonymity. Learn more about your ability to control Question Security today.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Article by: Kraeven
Introduction Remote Share is a simple remote sharing tool, enabling you to see, add and remove remote or local shares. The application is written in VB.NET targeting the .NET framework 2.0. The source code and the compiled programs have been in…
Since .Net 2.0, Visual Basic has made it easy to create a splash screen and set it via the "Splash Screen" drop down in the Project Properties.  A splash screen set in this manner is automatically created, displayed and closed by the framework itsel…
Exchange organizations may use the Journaling Agent of the Transport Service to archive messages going through Exchange. However, if the Transport Service is integrated with some email content management application (such as an anti-spam), the admin…
We’ve all felt that sense of false security before—locking down external access to a database or component and feeling like we’ve done all we need to do to secure company data. But that feeling is fleeting. Attacks these days can happen in many w…
Suggested Courses

755 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question