-
Mar 8th, 2018, 01:50 AM
#1
Thread Starter
Frenzied Member
[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
-
Mar 8th, 2018, 02:17 AM
#2
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.
-
Mar 8th, 2018, 03:43 AM
#3
Thread Starter
Frenzied Member
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.
-
Mar 8th, 2018, 04:09 AM
#4
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:
Me.txt1.Text = cnt1 If CInt(txt1.Text) > 0 Then txt1.BackColor = Color.Gold 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.
Last edited by jmcilhinney; Mar 8th, 2018 at 04:45 AM.
-
Mar 8th, 2018, 04:58 AM
#5
Thread Starter
Frenzied Member
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.
-
Mar 8th, 2018, 06:24 AM
#6
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|