Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

Thread Safe Calls

Posted on 2006-10-19
11
Medium Priority
?
805 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
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

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

Question has a verified solution.

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

1.0 - Introduction Converting Visual Basic 6.0 (VB6) to Visual Basic 2008+ (VB.NET). If ever there was a subject full of murkiness and bad decisions, it is this one!   The first problem seems to be that people considering this task of converting…
Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
In this video, Percona Director of Solution Engineering Jon Tobin discusses the function and features of Percona Server for MongoDB. How Percona can help Percona can help you determine if Percona Server for MongoDB is the right solution for …
Please read the paragraph below before following the instructions in the video — there are important caveats in the paragraph that I did not mention in the video. If your PaperPort 12 or PaperPort 14 is failing to start, or crashing, or hanging, …
Suggested Courses

636 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