You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多窗体跨线程刷新报错,求助Invoke实现方案

解决跨线程刷新多窗体控件的Invoke实现方案

核心原理

Windows窗体控件仅允许由创建它的线程(UI线程)访问,跨线程直接操作控件会触发System.InvalidOperationException。解决方法是通过Control.Invoke方法,将UI操作委托给控件所在的UI线程执行。

修改后的完整代码

Public Shared Sub VerificaAlterações(ByVal MOV_Bancos As List(Of Integer), ByVal MOV_Lançamentos As List(Of Integer), ByVal MOV_Datas As List(Of Date), ByVal DOC_Lojas As List(Of Integer), ByVal DOC_Clientes As List(Of Integer), ByVal DOC_BACs As List(Of String), ByVal DOC_Condições As List(Of Integer), ByVal DOC_Datas As List(Of Date), ByVal DOC_Sacados As List(Of String), ByVal DOCS_Documentos As List(Of String), ByVal DOC_Valores As List(Of Decimal))
    Dim n As Integer = 0

    For Each FormRefresh As Form In Application.OpenForms()

        Select Case FormRefresh.Name

            Case Form1.Name
                n = 0
                For Each BAC In DOC_BACs
                    ' 检查是否需要跨线程调用
                    If FormRefresh.InvokeRequired Then
                        ' 通过Invoke将操作委托给UI线程执行
                        FormRefresh.Invoke(Sub()
                                              DirectCast(FormRefresh, Form1).Btn1.PerformClick()
                                          End Sub)
                    Else
                        DirectCast(FormRefresh, Form1).Btn1.PerformClick()
                    End If
                    n += 1
                Next

            Case Form2.Name
                n = 0
                For Each BAC In DOC_BACs
                    ' 捕获当前循环的n值,避免闭包变量问题
                    Dim currentN = n
                    If FormRefresh.InvokeRequired Then
                        FormRefresh.Invoke(Sub()
                                              Dim form2 = DirectCast(FormRefresh, Form2)
                                              If (form2.tbLoja.Text = DOC_Lojas(currentN).ToString OrElse form2.tbLoja.Text = vbNullString OrElse CInt(form2.tbLoja.Text) = 0) AndAlso
                                                 (form2.tbCliente.Text = DOC_Clientes(currentN).ToString OrElse form2.tbCliente.Text = vbNullString OrElse CInt(form2.tbCliente.Text) = 0) AndAlso
                                                 (form2._procNome.Text = vbNullString OrElse form2._procNome.Text.Contains(DOC_Sacados(currentN))) AndAlso
                                                 (form2._procDcto.Text = vbNullString OrElse form2._procNome.Text.Contains(DOCS_Documentos(currentN))) AndAlso
                                                 (form2._procVlrCond.SelectedIndex = 0) AndAlso
                                                 (form2._pVenc1.Checked = False OrElse form2._pVenc1.Value <= DOC_Datas(currentN)) AndAlso
                                                 (form2._pVenc2.Checked = False OrElse form2._pVenc2.Value >= DOC_Datas(currentN)) Then
                                                  form2.BTN_Pesquisar.PerformClick()
                                                  Exit For
                                              End If
                                          End Sub)
                    Else
                        Dim form2 = DirectCast(FormRefresh, Form2)
                        If (form2.tbLoja.Text = DOC_Lojas(currentN).ToString OrElse form2.tbLoja.Text = vbNullString OrElse CInt(form2.tbLoja.Text) = 0) AndAlso
                           (form2.tbCliente.Text = DOC_Clientes(currentN).ToString OrElse form2.tbCliente.Text = vbNullString OrElse CInt(form2.tbCliente.Text) = 0) AndAlso
                           (form2._procNome.Text = vbNullString OrElse form2._procNome.Text.Contains(DOC_Sacados(currentN))) AndAlso
                           (form2._procDcto.Text = vbNullString OrElse form2._procNome.Text.Contains(DOCS_Documentos(currentN))) AndAlso
                           (form2._procVlrCond.SelectedIndex = 0) AndAlso
                           (form2._pVenc1.Checked = False OrElse form2._pVenc1.Value <= DOC_Datas(currentN)) AndAlso
                           (form2._pVenc2.Checked = False OrElse form2._pVenc2.Value >= DOC_Datas(currentN)) Then
                            form2.BTN_Pesquisar.PerformClick()
                            Exit For
                        End If
                    End If
                    n += 1
                Next

            Case Form3.Name
                n = 0
                For Each BAC In DOC_BACs
                    If FormRefresh.InvokeRequired Then
                        FormRefresh.Invoke(Sub()
                                              Dim form3 = DirectCast(FormRefresh, Form3)
                                              For Each Linha As DataGridViewRow In form3.tabDocumentos.Rows
                                                  With Linha.DefaultCellStyle
                                                      .ForeColor = Color.Black
                                                      .SelectionBackColor = Color.Black
                                                  End With
                                              Next
                                          End Sub)
                    Else
                        Dim form3 = DirectCast(FormRefresh, Form3)
                        For Each Linha As DataGridViewRow In form3.tabDocumentos.Rows
                            With Linha.DefaultCellStyle
                                .ForeColor = Color.Black
                                .SelectionBackColor = Color.Black
                            End With
                        Next
                    End If
                    n += 1
                Next

        End Select
    Next
End Sub

关键注意事项

  • InvokeRequired判断:每次访问UI控件前必须检查该属性,确保操作在正确的线程执行
  • 闭包变量处理:在循环中使用currentN捕获当前循环的n值,避免Lambda表达式引用同一变量导致的逻辑错误
  • 委托简化:使用VB.NET的匿名Sub(Lambda表达式)直接封装UI操作,无需额外定义委托类型
  • 窗体类型转换:通过DirectCast将通用Form对象转换为具体窗体类型,以访问其专属控件和方法

内容的提问来源于stack exchange,提问作者Heitor Badotti

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 01:31:08