开发者

Stackoverflow error in BackgroundWorker ProgressChanged

开发者 https://www.devze.com 2023-04-08 15:13 出处:网络
I have a search function in my program that uses a background worker in order to get the results. The Progress changed event is used to update the listview with the new item.

I have a search function in my program that uses a background worker in order to get the results. The Progress changed event is used to update the listview with the new item.

Private Sub SearchWorker_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles SearchWorker.ProgressChanged
    Dim itmX As ListViewItem
    Dim tmpCustomer As CustomerItem

    If e.UserState.ToString = "New" Then
        lstResults.Items.Clear()
    Else
        Try
            tmpCustomer = e.UserState
            itmX = lstResults.Items.Add(tmpCustomer.CustomerName) ' <-- Error here
            itmX.Tag = tmpCustomer.CustomerID
            itmX.Name = tmpCustomer.CustomerID
            itmX.SubItems.Add(tmpCustomer.City)
            itmX.SubItems.Add(tmpCustomer.State)
            itmX.SubItems.Add(tmpCustomer.Zip)
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End If

    progBar.Value = e.ProgressPercentage

    Application.DoEvents()
End Sub

And I get this error

An unhandled exception of type 'System.StackOverflowException' occurred in System.Windows.Forms.dll

I've tried this, but it doesn't make a difference

Private Sub SearchWorker_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles SearchWorker.ProgressChanged

    If e.UserState.ToString = "New" Then
        lstResults.Items.Clear()
    Else
        Try
            itmX = lstResults.Items.Add("Test")
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End If

    progBar.Value = e.ProgressPercentage

    Application.DoEvents()
End Sub

Edit: Oh, and if I just step through the code, it doesn't have any problems.

Edit 2:

Here is the backgroundworker DoWork event:

Sub doSearch(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles SearchWorker.DoWork
    canceled = False
    If curSearch = doSearchText Then
        canceled = True
        Exit Sub
    End If
    curSearch = doSearchText

    SearchWorker.ReportProgress(0, "New")
    Dim rSelect As New ADODB.Recordset
    Dim CustomerID As Integer = MakeNumeric(doSearchText)
    Dim sSql As String = "SELECT DISTINCT CustomerID, CustomerName, City, State, Zip FROM qrySearchFieldsQuick WHERE "
    Dim sWhere As String = "CustomerID = " & CustomerID & " OR CustomerName Like '" & doSearchText & "%'"
    If Not doSearchText.Contains(" ") Then
        sWhere &= " OR FirstName Like '" & doSearchText & "%' OR LastName Like '" & doSearchText & "%'"
    Else
        Dim str() As String = doSearchText.Split(" ")
        sWhere &= " OR (FirstName Like '" & str(0) & "%' AND LastName Like '" & str(1) & "%')"
    End If

    Dim i As Integer = 0
    Dim tmpCustomer As CustomerItem

    With rSelect
        .Open(sSql & sWhere & " ORDER BY CustomerName", MyCn, ADODB.CursorTypeEnum.adOpenStatic, ADODB.LockTypeEnum.adLockReadOnly)
        Do While Not .EOF
            If SearchWorker.CancellationPending Then
                canceled = True
                Exit Do
            End If

            Do While IsDBNull(.Fields("CustomerID").Value)
                .MoveNext()
            Loop

            tmpCustomer.CustomerID = "c" & .Fields("CustomerID").Value
            tmpCustomer.CustomerName = NZ(.F开发者_如何学Goields("CustomerName").Value, "").ToString.Trim
            tmpCustomer.City = Trim(NZ(.Fields("City").Value, ""))
            tmpCustomer.State = Replace(Trim(NZ(.Fields("State").Value, "")), ",", "")
            tmpCustomer.Zip = Trim(NZ(.Fields("Zip").Value, ""))

            SearchWorker.ReportProgress((i / .RecordCount) * 100, tmpCustomer)
            i += 1
            Application.DoEvents()
aMoveNext:

            .MoveNext()
        Loop
        .Close()
    End With
End Sub


I think the problem is likely this line:

Application.DoEvents()

If your BackgroundWorker is queueing up ProgressChanged events fast enough, each call to Application.DoEvents() will work through the message queue, come to a ProgressChanged event, update the progress, call Application.DoEvents(), work through the message queue, come to a ProgressChanged event, etc.. essentually causing a recursive behavior in your code.

Try removing that call and see if the problem goes away.


Application.DoEvents()

That's the trouble maker. You added it because you noticed that the user interface still froze, even though you used a BGW. Problem is, when it pumps the events, your BGW has called ReportProgress again. Causing ProgressChanged to run again. Causing DoEvents to get called again. That works for maybe a few seconds until the ui thread runs out of stack space. Kaboom.

You'll have to delete the DoEvents() call. And solve the real problem, your BGW is calling ReportProgress way too often. Causing the ui thread to be flooded with invoke requests to call ProgressChanged. Causing it to no longer take care of its regular duties. Including painting and responding to user input.

Call ReportProgress not more often than 20 times per second. That looks smooth to the human eye. Collect calculation results so you'll have a bunch of work ready to process. If your worker produces results faster than the ui thread can display them then you have no option but to slow it down forcefully.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号