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