Solved

Thread Safe Calls

Posted on 2006-10-19
11
753 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 100 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
 
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
Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

 
LVL 9

Accepted Solution

by:
DjDezmond earned 400 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

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

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…
Parsing a CSV file is a task that we are confronted with regularly, and although there are a vast number of means to do this, as a newbie, the field can be confusing and the tools can seem complex. A simple solution to parsing a customized CSV fi…
This tutorial demonstrates a quick way of adding group price to multiple Magento products.
This video demonstrates how to create an example email signature rule for a department in a company using CodeTwo Exchange Rules. The signature will be inserted beneath users' latest emails in conversations and will be displayed in users' Sent Items…

747 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

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now