Переадресация минимальных и максимальных значений BackgroundWorker для правильного использования функции - PullRequest
0 голосов
/ 24 февраля 2020

В течение нескольких дней я изо всех сил пытался найти решение о том, как правильно включить BackgroundWorker в мою функцию, и благодаря этому у меня есть возможность правильно отображать процесс разработки, процесс остановки, отчет.

это мой код

 Private Sub Frm_ImportLeumobileGK_FormClosing(sender As Object, e As Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
        Me.BackgroundWorker1.CancelAsync()
        Me.Timer1.Enabled = False
        Me.DialogResult = DialogResult.Cancel
        e.Cancel = True
    End Sub

     Private Sub Btn_OK_Click(sender As Object, e As EventArgs) Handles btn_OK.Click
        ListView1.Items.Clear()
        resetCounter()
        BackgroundWorker1.RunWorkerAsync()
    End Sub


      Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        Dim worker As BackgroundWorker = TryCast(sender, BackgroundWorker)
        TestPut_All_CDRs_To_FakturaPos(worker, e,
                         MasterMandantConnectionString:=MasterMandantConnectionString,
                         StartDate:=dtp_Start.Value,
                         EndDate:=dtp_End.Value,
                         min_Nr:=tb_Min_Nr.Value,
                         max_Nr:=tb_Max_Nr.Value)
    End Sub

      Sub TestPut_All_CDRs_To_FakturaPos(worker As BackgroundWorker, e As DoWorkEventArgs, MasterMandantConnectionString As String, StartDate As Date, EndDate As Date, min_Nr As Integer, max_Nr As Integer)
        Dim n As Integer = 0
        Dim MobCdrs As List(Of String)
        ProgressBar1.Maximum = (max_Nr - min_Nr)

        For Mob_Nr = min_Nr To max_Nr
            n += 1
            If worker.CancellationPending Then
                e.Cancel = True
            Else
                MobCdrs = TestPut_Mob_CDRs_To_FakturaPos(MasterMandantConnectionString:=MasterMandantConnectionString,
                                   StartDate:=StartDate,
                                   EndDate:=EndDate,
                                   Mob_Nr:=Mob_Nr)
                For Each currentError In MobCdrs
                    If (currentError <> "") Then
                        ListView1.Items.Add(currentError)
                    End If
                Next
                If n > ProgressBar1.Maximum Then
                    n = ProgressBar1.Maximum
                End If
                ProgressBar1.Value = n
            End If
        Next
        ListView1.Items.Insert(0, getImportInfo(), 0)
        labelInfo.Text = "Test successfully completed."
    End Sub
  Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
        ProgressBar1.Value = e.ProgressPercentage
    End Sub

    Private Sub Frm_FormClosing(sender As Object, e As Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing 
If BackgroundWorker1 IsNot Nothing Then
        Me.BackgroundWorker1.CancelAsync()
        Me.Close()
    End If

End Sub

Используя Документация , я попытался применить BackgroundWorker к моей функции "TestPut_All_CDRs_To_FakturaPos", к сожалению, не удалось, потому что я попал в ProgressBar1.Maximum error = *** "System.InvalidOperationException:" Недопустимая операция перекрестного потока: доступ к элементу управления ProgressBar1 был получен из потока, отличного от потока, для которого он был создан. "*** Пожалуйста, предложите, где я делаю исключение?

1 Ответ

1 голос
/ 25 февраля 2020

Что вам нужно сделать, это отделить части пользовательского интерфейса (такие как ListViews, MessageBoxes и т. Д. c.) От фонового работника.

  • Способ передачи данных в BGW заключается в передать объект в .Argument.
  • Чтобы извлечь из него данные во время его работы, используйте событие ReportProgress и передайте все, что вы хотите, в .UserState объект.
  • Чтобы получить данные из него после его завершения, используйте свойство .Result.

Мы не будем использовать какой-либо результат в этом случае, но я установлю его как логическое значение, если вы хотите изменить его. Итак, давайте создадим классы для ввода и вывода данных ...

Private Class BgwArgs
    Property StartDate As DateTime
    Property EndDate As DateTime

    Property MinNr As Integer
    Property MaxNr As Integer

    Property ConnStr As String

End Class

Private Class ProgressReportData
    Property ErrorMessages As List(Of String)

End Class

Первоначальная настройка BGW выглядит следующим образом:

Private Sub Btn_OK_Click(sender As Object, e As EventArgs) Handles Btn_OK.Click
    ListView1.Items.Clear()
    ResetCounter()

    Dim args As New BgwArgs With {.StartDate = dtp_Start.Value,
                                  .EndDate = dtp_End.Value,
                                  .MinNr = CInt(tb_Min_Nr.Value),
                                  .MaxNr = CInt(tb_Max_Nr.Value),
                                  .ConnStr = "your connection string"}

    ProgressBar1.Minimum = 0
    ProgressBar1.Maximum = 100

    BackgroundWorker1.WorkerReportsProgress = True
    BackgroundWorker1.WorkerSupportsCancellation = True

    BackgroundWorker1.RunWorkerAsync(args)

End Sub

, а затем все части:

Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    Dim worker As BackgroundWorker = TryCast(sender, BackgroundWorker)

    e.Result = TestPut_All_CDRs_To_FakturaPos(worker, e)

End Sub

Private Function TestPut_All_CDRs_To_FakturaPos(worker As BackgroundWorker, e As DoWorkEventArgs) As Boolean

    Dim importedInfo As New List(Of String)

    Dim args = CType(e.Argument, BgwArgs)
    Dim masterMandantConnectionString = args.ConnStr
    Dim startDate = args.StartDate
    Dim endDate = args.EndDate
    Dim min_Nr = args.MinNr
    Dim max_Nr = args.MaxNr

    Dim n As Integer = 0
    Dim totalMobs = max_Nr - min_Nr + 1

    For mob_Nr = min_Nr To max_Nr
        n += 1
        If worker.CancellationPending Then
            e.Cancel = True
        Else
            Dim mobCdrs = TestPut_Mob_CDRs_To_FakturaPos(MasterMandantConnectionString:=masterMandantConnectionString,
                               StartDate:=startDate,
                               EndDate:=endDate,
                               Mob_Nr:=mob_Nr)

            Dim pct = n * 100 \ totalMobs
            Dim progReport As New ProgressReportData With {.ErrorMessages = mobCdrs.Where(Function(m) Not String.IsNullOrEmpty(m)).ToList()}

            worker.ReportProgress(pct, progReport)

        End If
    Next

    Return True

End Function

Private Sub backgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
    Dim progData = CType(e.UserState, ProgressReportData)
    ProgressBar1.Value = e.ProgressPercentage
    If progData.ErrorMessages IsNot Nothing Then
        For Each m In progData.ErrorMessages
            ListView1.Items.Add(m)
        Next
    End If

End Sub

Private Sub backgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
    If (e.Error IsNot Nothing) Then
        ProgressBar1.ForeColor = Color.Red
        MessageBox.Show(e.Error.Message, "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error)

    ElseIf e.Cancelled Then
        ' Next, handle the case where the user cancelled the operation.
        ' Note that due to a race condition in the DoWork event handler, the Cancelled flag may not have been set, even though CancelAsync was called.
        ProgressBar1.ForeColor = Color.HotPink

    Else
        ProgressBar1.ForeColor = Color.LawnGreen
        ListView1.Items.Insert(0, GetImportInfo(), 0)
        labelInfo.Text = "Test successfully completed."

        ' We could use e.Result here if something useful was returned in it.
        ' Dim flag = CType(e.Result, Boolean)

    End If

End Sub

Процент прогресса вычисляется в l oop, поскольку это простой способ сделать это.

Я не смог проверить это, но, надеюсь, там достаточно для вас чтобы получить рабочий код.

(я использую Option Infer On и Option Strict On.)

...