我有一个由分析测试组成的Windows应用程序。当用户选择特定测试时,这些测试在后台线程中运行。在后台输入文件(在excel中,文本中)在SQL中加载并执行相应的查询并将输出粘贴到excel中。
现在我已经实现了一些关于输入文件是否正确的验证等等。后台线程。
之前它在UI线程中使用CreateWait()函数显示了用户在表格布局面板中选择的所有测试。但现在验证后我需要在表格布局面板中仅显示经过验证的测试。现在我想在后台线程中更新Panel。但是它给了我错误“交叉线程操作无效”,说Panel是从与创建它的线程不同的线程访问的。
以下是我的代码:(我只是只显示特定的代码/功能,以便读者了解流程)
Private Sub Btn_run_Click(sender As Object, e As EventArgs) Handles btn_run.Click
CreateWait()
BackgroundWorker1.RunWorkerAsync()
End Sub
下面是我从UI线程调用的CreateWait()方法,我想从后台线程中调用它。
Public Sub CreateWait()
Dim ratio1 As Double = 0
Dim ratio2 As Double = 0
If currstate = 2 Then
ratio1 = maxwidth / panelwidth
ratio2 = maxheight / panelheight
End If
Dim TestArray As Array
Dim EachTest As Array
'ExecutionWait.TestsIdName = TestsIdName
TestArray = Split(TestsIdName, ";")
Dim Pnl2 As New Panel With {
.Location = New System.Drawing.Point(30, 80),
.Anchor = AnchorStyles.None,
.Dock = DockStyle.None,
.AutoScroll = True,
.Size = New Size(946, 345),
.Margin = New Padding(0, 0, 0, 0),
.Padding = New Padding(0, 0, 0, 0),
.BackColor = Color.Transparent
}
Pnl2.HorizontalScroll.Visible = False
Pnl2.HorizontalScroll.Enabled = False
Pnl2.BorderStyle = BorderStyle.None
Pnl2.Name = "panel_output"
ExecutionWaitPanel.Controls.Add(Pnl2)
If currstate = 2 Then
Pnl2.Location = New Point(Pnl2.Left * ratio1, Pnl2.Top * ratio2)
Pnl2.Size = New Size(Pnl2.Width * ratio1, Pnl2.Height * ratio2)
End If
Dim tlp2 As New TableLayoutPanel With {
.Location = New System.Drawing.Point(0, 0),
.Dock = DockStyle.None,
.AutoScroll = False,
.AutoSize = True,
.Margin = New Padding(0, 0, 0, 0),
.Padding = New Padding(0, 0, 0, 0),
.BackColor = Color.Transparent,
.ColumnCount = 3,
.RowCount = UBound(TestArray)
}
下面是Background_worker的代码,我在其中调用ColumnMapping函数进行验证,并希望通过调用CreateWait()函数来更新ExecutionWaitPanel,但是给我的跨线程操作无效。
Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Call ColumnMapping(qwe, dt1.Rows(0)("input_path"))
CreateWait()
End Sub
答案 0 :(得分:0)
您无法从其创建的其他线程访问GUI。所以,要完成你想要的东西,我建议采用以下两种方法之一:
<强> 1。从父表单调用GUI方法。 (我不是真的推荐使用这种方法,但它会起作用)
在BackGroundWorker.DoWork事件中放置以下语句
Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Call ColumnMapping(qwe, dt1.Rows(0)("input_path"))
Me.Invoke(sub() CreateWait())
End Sub
<强> 2。使用Task.Run()
从您的代码中移除BackGroundWorker
,因为它不再需要,并使用Task.Run()
来阻止您的用户界面。
将Button.Click提升为Async方法并运行其中的所有内容。
Private async Sub Btn_run_Click(sender As Object, e As EventArgs) Handles btn_run.Click
CreateWait()
Await Task.Run(Sub() Call ColumnMapping(qwe, dt1.Rows(0)("input_path")))
CreateWait()
End Sub
这样,它首先会在您的用户界面上调用CreateWait()
方法,运行任务&#39; Asyncrhonosly&#39;当它完成后,它将再次运行CreateWait()
。