Results 1 to 6 of 6

Thread: [RESOLVED] Background worker cross-thread operation not valid

Hybrid View

  1. #1

    Thread Starter
    Frenzied Member
    Join Date
    Apr 2016
    Posts
    1,415

    Resolved [RESOLVED] Background worker cross-thread operation not valid

    Hi. I have a form that is performing many calculations. Sometimes this can take maybe 10 seconds or more. In this time I wish to show user that it is busy. So I have create a progress bar (Marquee) and have put it inside panel.

    So when this form is busy calculate I show progress bar. My problem is a cross-thread error. Here is my code:

    Code:
    Public Class frmCountHazards
    
        Private Sub frmCountHazards_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    
            MyProgressBar.Visible = True
            BackgroundWorker1.RunWorkerAsync()
        End Sub
    
        'BACKGOUNDWORKER = START
    
        Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    
            Dim con As New SqlClient.SqlConnection(My.Settings.RiskDBConnectionString)
            con.Open()
    
    'this is calculation. there are many more but I only put one to demonstrate. 
    
            Dim cmd1 As New SqlClient.SqlCommand("Select COUNT(tblRiskAssessment.Hazard) as TOTALS_Risks FROM tblContext LEFT OUTER JOIN tblRiskAssessment ON tblContext.ContextID = tblRiskAssessment.ContextID WHERE (tblContext.ContextID LIKE @ContextID) AND (tblRiskAssessment.Hazard = 'Stairs')", con)
            cmd1.Parameters.AddWithValue("ContextID", MyGlobalVariableContextID)
            Dim cnt1 As Integer = CInt(cmd1.ExecuteScalar)
    
    this is where I get error:
           
     Me.TextBox1.Text = cnt1
       
     End Sub
    
        Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
    
            If e.Error IsNot Nothing Then
                '' if BackgroundWorker terminated due to error
                MessageBox.Show(e.Error.Message)
    
    
            ElseIf e.Cancelled Then
                '' otherwise if it was cancelled
                MessageBox.Show("Task cancelled!")
    
            Else
                'otherwise it completed normally
                MyProgressBar.Visible = False
    
                MsgBox("Done", vbInformation, "Done")
                Me.Enabled = True
            End If
        End Sub
    
        'BACKGOUNDWORKER = END
    End Class

  2. #2
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: Background worker cross-thread operation not valid

    Must not have read the documentation.
    You need to ReportProgress from the backgroundworker and handle the ProgressChanged event to update GUI controls. You can't update GUI controls directly from another thread. There is an example that is updating a textbox at the above link.

    Ack, wrong document. That is silverlight. Just a minute.

    The winform version is still pretty much the same methods.
    https://msdn.microsoft.com/en-us/lib...v=vs.110).aspx
    Last edited by passel; Mar 8th, 2018 at 02:21 AM.

  3. #3

    Thread Starter
    Frenzied Member
    Join Date
    Apr 2016
    Posts
    1,415

    Re: Background worker cross-thread operation not valid

    Hi I was reading that documentation and I have create example. In post #1 I have said that my progress bar is "Marquee" - for this means that I don't want to report progress. The progress bar must just run until all calculations are finish.

    Anyhow, I did this in the example and still produce very same error.



    Code:
    Imports System.ComponentModel
    
    Public Class Form1
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    
        End Sub
        Public Sub New()
            InitializeComponent()
            BackgroundWorker1.WorkerReportsProgress = True
            BackgroundWorker1.WorkerSupportsCancellation = True
        End Sub
    
        Private Sub startAsyncButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles startAsyncButton.Click
            If BackgroundWorker1.IsBusy <> True Then
                ' Start the asynchronous operation.
                BackgroundWorker1.RunWorkerAsync()
            End If
        End Sub
    
        Private Sub cancelAsyncButton_Click(ByVal sender As System.Object,
        ByVal e As System.EventArgs) Handles cancelAsyncButton.Click
            If BackgroundWorker1.WorkerSupportsCancellation = True Then
                ' Cancel the asynchronous operation.
                BackgroundWorker1.CancelAsync()
            End If
        End Sub
    
        ' This event handler is where the time-consuming work is done.
        Private Sub backgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    
            Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)
            Dim i As Integer
    
            For i = 1 To 10
                If (worker.CancellationPending = True) Then
                    e.Cancel = True
                    Exit For
                Else
                    ' Perform a time consuming operation and report progress.
                    ' This is where calculations is done
    
                    Dim con As New SqlClient.SqlConnection(My.Settings.RiskDBConnectionString)
                    con.Open()
                    Dim cmd1 As New SqlClient.SqlCommand("Select COUNT(tblRiskAssessment.Hazard) as TOTALS_Risks FROM tblContext LEFT OUTER JOIN tblRiskAssessment ON tblContext.ContextID = tblRiskAssessment.ContextID WHERE (tblContext.ContextID LIKE @ContextID) AND (tblRiskAssessment.Hazard = 'Ablution Facilities')", con)
                    cmd1.Parameters.AddWithValue("ContextID", MyGlobalVariableContextID)
                    Dim cnt1 As Integer = CInt(cmd1.ExecuteScalar)
                    Me.txt1.Text = cnt1
                    If CInt(txt1.Text) > 0 Then
                        txt1.BackColor = Color.Gold
                    End If
    
                    System.Threading.Thread.Sleep(500)
                    worker.ReportProgress(i * 10)
                End If
            Next
        End Sub
    
        ' This event handler updates the progress.
        Private Sub backgroundWorker1_ProgressChanged(ByVal sender As System.Object, ByVal e As ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
            resultLabel.Text = (e.ProgressPercentage.ToString() + "%")
        End Sub
    
        ' This event handler deals with the results of the background operation.
        Private Sub backgroundWorker1_RunWorkerCompleted(ByVal sender As System.Object,
        ByVal e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
            If e.Cancelled = True Then
                resultLabel.Text = "Canceled!"
            ElseIf e.Error IsNot Nothing Then
                resultLabel.Text = "Error: " & e.Error.Message
            Else
                resultLabel.Text = "Done!"
            End If
        End Sub
    
    End Class


    Attachment 157089
    Last edited by schoemr; Mar 8th, 2018 at 03:46 AM.

  4. #4
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,344

    Re: Background worker cross-thread operation not valid

    Of course you get the same error. This is in your DoWork event handler:
    vb.net Code:
    1. Me.txt1.Text = cnt1
    2. If CInt(txt1.Text) > 0 Then
    3.     txt1.BackColor = Color.Gold
    4. End If
    That's three times you try to manipulate a control on the background thread. It's very simple: DO NOT manipulate a control in the DoWork event handler or in a method called from the DoWork event handler. That method is executed on a secondary thread, which is the whole point. If you want to update the UI during the work then call ReportProgress and update the UI in the ProgressChanged event handler. Why would you have to do that to specifically update progress but not for any other UI manipulation? The documentation for the BackgroundWorker class says this:
    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.

  5. #5

    Thread Starter
    Frenzied Member
    Join Date
    Apr 2016
    Posts
    1,415

    Re: Background worker cross-thread operation not valid

    DO NOT manipulate a control in the DoWork event handler or in a method called from the DoWork event handler
    Awesome! Thanks John

    It is working now. I make note of this not to forget.

  6. #6
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,344

    Re: [RESOLVED] Background worker cross-thread operation not valid

    Better to make a note to always read the documentation for the types and/or members you're using. I feel like I must have mentioned that before.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width