【问题标题】:Forwarding the min and max values of BackgroundWorker to use the function correctly转发 BackgroundWorker 的最小值和最大值以正确使用该函数
【发布时间】:2020-02-24 08:17:41
【问题描述】:

几天来,我一直在努力寻找如何将 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 控件来自创建它的线程以外的线程。”***请建议,我在哪里例外?

【问题讨论】:

    标签: vb.net backgroundworker


    【解决方案1】:

    您需要做的是将用户界面部分(如 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。)

    【讨论】:

    • @Mara 我猜你是通过将 BGW 拖到设计器中的窗体上创建的,在这种情况下,请选择它,然后按 F4 显示其属性,并将 WorkerReportsProgress 和 WorkerSupportsCancellation 更改为 True。希望这将使一切正常!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-27
    • 2015-10-29
    • 2013-09-28
    • 2021-01-24
    • 2020-09-02
    • 2017-06-30
    相关资源
    最近更新 更多