交叉线程操作无效

时间:2017-05-24 08:07:16

标签: .net vb.net multithreading

我有一个由分析测试组成的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

1 个答案:

答案 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()