Ошибка переполнения стека в BackgroundWorker ProgressChanged - PullRequest
1 голос
/ 27 сентября 2011

В моей программе есть функция поиска, которая использует фоновый рабочий для получения результатов.Событие «Изменение прогресса» используется для обновления представления списка новым элементом.

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

И я получаю эту ошибку

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

Я пробовал это, но это не делаетразница

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

Редактировать: О, и если я просто пошагово по коду, у него не будет никаких проблем.

Редактировать 2:
Вот событие DoWork фонового работника:

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(.Fields("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

Ответы [ 2 ]

6 голосов
/ 27 сентября 2011

Я думаю, что проблема, вероятно, в этой строке:

Application.DoEvents()

Если ваш BackgroundWorker ставит в очередь события ProgressChanged достаточно быстро, каждый вызов Application.DoEvents() будет проходить через очередь сообщений, приходить на событие ProgressChanged, обновлять ход выполнения, вызывать Application.DoEvents(), работать через очередь сообщений, событие ProgressChanged и т. д., в основном вызывающее рекурсивное поведение в вашем коде.

Попробуйте удалить этот вызов и посмотрите, исчезнет ли проблема.

5 голосов
/ 27 сентября 2011
Application.DoEvents()

Это источник проблем. Вы добавили его, потому что заметили, что пользовательский интерфейс все еще завис, хотя вы использовали BGW. Проблема в том, что при прокачке событий ваш BGW снова вызывает ReportProgress. Вызывает ProgressChanged для запуска снова. Вызывает DoEvents для повторного вызова. Это работает в течение нескольких секунд, пока поток пользовательского интерфейса не исчерпает пространство стека. Kaboom.

Вам придется удалить вызов DoEvents (). И решить реальную проблему, ваш BGW слишком часто вызывает ReportProgress way . Вызывает поток пользовательского интерфейса с запросами вызова для вызова ProgressChanged. Причинение этого больше не заботиться о его регулярных обязанностях. Включая рисование и реагирование на ввод пользователя.

Вызовите ReportProgress не чаще, чем 20 раз в секунду. Это выглядит гладко для человеческого глаза. Соберите результаты расчетов, чтобы у вас была куча работы, готовой к обработке. Если ваш работник выдает результаты быстрее, чем поток пользовательского интерфейса может их отобразить, у вас нет другого выбора, кроме как принудительно замедлить его.

...