转发 BackgroundWorker 的最小值和最大值以正确使用该功能

Forwarding the min and max values of BackgroundWorker to use the function correctly

几天来,我一直在努力寻找一个解决方案,以找到如何将 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

结束子

使用 Documentation,我尝试将 BackgroundWorker 应用到我的“TestPut_All_CDRs_To_FakturaPos”函数,不幸的是失败了,因为我遇到 ProgressBar1.Maximum error = ***System.InvalidOperationException :“无效的跨线程操作:ProgressBar1 控件是从创建它的线程以外的线程访问的。”***请建议,我在哪里制造异常?

您需要做的是将用户界面部分(如 ListViews、MessageBoxes 等)与后台工作程序分开。

  • 将数据放入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

进度百分比是在循环中计算的,因为这是完成它的简单方法。

我无法对其进行测试,但希望您可以获得足够的代码。

(我使用 Option Infer On 和 Option Strict On。)