none
Cross-thread operation not valid: Control 'ProgressBar1' accessed from a thread other than the thread it was created on.

    Question

  • Run the code from support.microsoft.com/kb/315577 

    This a threading example codes.

    But the following error occured.

    "Cross-thread operation not valid: Control 'ProgressBar1' accessed from a thread other than the thread it was created on."

    How can I solve it ?

    Sunday, February 17, 2013 6:27 AM

Answers

  • My answer is "yes, it's fine - you're not touching any UI objects", but most here will say "NO! - you're reaching across the threads!"

    I've challenged in the past to show me where this is a violation - I've looked and I can't find anything. Specifically I reference this from MSDN, which in part states as follows:

    "You must be careful not to manipulate any user-interface objects in your DoWork event handler. Instead, communicate to the user interface through the ProgressChanged and RunWorkerCompleted events."

    What you do NOT see there is any mention of what you're doing. You are NOT manipulating any UI objects, so I think it's fine and I've done it many many times with yet a hint of an issue.

    I'm sure this will raise the ire of many when I post this so ... hang on, here we go for a ride! ;-)


    Please call me Frank :)

    Sunday, February 17, 2013 10:32 PM

All replies

  • The earliest releases of the .Net Framework and Visual Studio did not check for these illegal cross-thread calls.  Perhaps the example you are using was originally written for this version of the framework and has not been updated.

    You can work around it (not recommended) or solve it by using the procedure described here:
    http://tech.xster.net/tips/invoke-ui-changes-across-threads-on-vb-net/

    Sunday, February 17, 2013 6:44 AM
  • take the same form with the button and progress bar, add a background worker, be sure to set the "Can Report Progress" to true and use this code:

    Public Class Form1
        Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
            MessageBox.Show("This is the main thread")
        End Sub
    
        Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
            BackgroundWorker1.RunWorkerAsync()
        End Sub
    
        Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
            Dim stp As Integer
            Dim newval As Integer
            Dim rnd As New Random()
    
            Do
                stp = ProgressBar1.Step * rnd.Next(-1, 2)
                newval = ProgressBar1.Value + stp
                If newval > ProgressBar1.Maximum Then
                    newval = ProgressBar1.Maximum
                ElseIf newval < ProgressBar1.Minimum Then
                    newval = ProgressBar1.Minimum
                End If
                BackgroundWorker1.ReportProgress(newval)
                System.Threading.Thread.Sleep(100)
            Loop
        End Sub
        Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
            ProgressBar1.Value = e.ProgressPercentage
        End Sub
    End Class

    Sunday, February 17, 2013 7:22 PM
  • Devon,

    If that doesn't thrown a cross-thread exception then it should.

    Don't "touch" the UI controls (the progressbar) inside the worker itself. I don't have a good suggestion for what you're trying to show but - what you have there isn't a good idea.

    You could, though, just start a loop and each nth time, use the worker's .ReportProgress to show how it could work.

    Not trying to be difficult - I hope you know that. :)


    Please call me Frank :)

    Sunday, February 17, 2013 7:29 PM
  • Not a problem Frank, I always appreciate constructive advice.

    Do you mean reading the ProgressBar value is not a good idea ?

    I do use the ReportProgress to update it and I always thought that was OK to do that.

    Sunday, February 17, 2013 9:34 PM
  • Not a problem Frank, I always appreciate constructive advice.

    Do you mean reading the ProgressBar value is not a good idea ?

    I do use the ReportProgress to update it and I always thought that was OK to do that.

    Right.

    If it's in the form, don't touch it. It'll catch up to you eventually and you'll wonder what happened!

    You can pass things in as parameters (e.Argument), pass them back out (e.Result) but in between, don't touch the UI things except through the .ReportProgress().

    It'll catch up to you unexpectedly too (been there, done that!). ;-)


    Please call me Frank :)

    Sunday, February 17, 2013 9:38 PM
  • Can this be done, using variables?

    Public Class Form1
        Dim PBCurVal As Integer
        Dim PBMaxVal As Integer
        Dim PBMinVal As Integer
        Dim PBStep As Integer
        Dim stp As Integer
    
        Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
            Dim newval As Integer
            Dim rnd As New Random()
    
            Do
                stp = PBStep * rnd.Next(-10, 11)
                newval = PBCurVal + stp
                If newval > PBMaxVal Then
                    newval = PBMaxVal
                ElseIf newval < PBMinVal Then
                    newval = PBMinVal
                End If
                BackgroundWorker1.ReportProgress(newval)
                System.Threading.Thread.Sleep(100)
            Loop
        End Sub
        Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
            ProgressBar1.Value = e.ProgressPercentage
        End Sub
    
        Private Sub Button1_Click_1(sender As System.Object, e As System.EventArgs) Handles Button1.Click
            MessageBox.Show("This is the main thread")
        End Sub
    
        Private Sub Form1_Load_1(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
            PBMaxVal = ProgressBar1.Maximum
            PBMinVal = ProgressBar1.Minimum
            PBStep = ProgressBar1.Step
            PBCurVal = ProgressBar1.Value
            BackgroundWorker1.RunWorkerAsync()
        End Sub
    End Class
    

    Sunday, February 17, 2013 10:21 PM
  • My answer is "yes, it's fine - you're not touching any UI objects", but most here will say "NO! - you're reaching across the threads!"

    I've challenged in the past to show me where this is a violation - I've looked and I can't find anything. Specifically I reference this from MSDN, which in part states as follows:

    "You must be careful not to manipulate any user-interface objects in your DoWork event handler. Instead, communicate to the user interface through the ProgressChanged and RunWorkerCompleted events."

    What you do NOT see there is any mention of what you're doing. You are NOT manipulating any UI objects, so I think it's fine and I've done it many many times with yet a hint of an issue.

    I'm sure this will raise the ire of many when I post this so ... hang on, here we go for a ride! ;-)


    Please call me Frank :)

    Sunday, February 17, 2013 10:32 PM