Unexpected\false positive error: 'Invoke or BeginInvoke cannot be called on a control until the window handle has been created'

Unexpected\false positive error: 'Invoke or BeginInvoke cannot be called on a control until the window handle has been created'

在特定的异步情况下,我收到一个 System.Reflection.TargetInvocationException 异常并显示此错误消息:

Invoke or BeginInvoke cannot be called on a control until the window handle has been created

请注意这不是一个重复的问题,我将在下面解释原因。我知道错误的含义,但不能 be/should 不抛出异常,因为 window 的句柄是在我的代码中创建的。

我开始认为我收到的这个错误消息可能是 .NET Framework 中的一个新错误,我需要有人的帮助来澄清这是否是我在代码中的错还是我的错,以及如何解决这个问题。

我只有这个 class 代表主要申请表:

Public NotInheritable Class Main : Inherits Form

    Private Async Sub ButtonMirror_Click(sender As Object, e As EventArgs) Handles ButtonMirror.Click

        ' Synchronous.
        ' Dim sucess As Boolean = MirrorUtil.BuildMirror

        ' Asynchronous.
        Dim t As Task(Of Boolean) = Task.Run(Of Boolean)(AddressOf MirrorUtil.BuildMirror)
        Dim sucess As Boolean = Await t

    End Sub

End Class

请注意,事件处理程序指定了 Async 关键字。

这是BuildMirror方法

Friend NotInheritable Class MirrorUtil

    Friend Shared Function BuildMirror() As Boolean
        My.Forms.Main.Invoke(Sub() My.Forms.Main.Visible = False)
    End Function

End Class

问题出在 BuildMirror 方法的块内,只有当我像上面的代码那样异步调用它时才会发生,Main.Invoke() 方法抛出提到的异常,如果我执行对 Main.IsHandleCreated 的调用,令人惊讶的是 returns False! ...只有当我异步调用 BuildMirror 方法时,我才坚持。

我想了解发生了什么,以及如何解决它。当然,主应用程序表单是实例化的并且是可见的,window 句柄已创建,那么它不应该抛出该异常...

我在尝试调试真正的问题时发现了这个奇怪的问题,这不是我在这个问题中暴露的问题,但是我认为这个奇怪的问题是我真正的问题的原因,所以我很感激一个解决方案为此。

我会简化这个。你不需要另一个 class.

Public NotInheritable Class Main : Inherits Form

    Private Async Sub ButtonMirror_Click(sender As Object, e As EventArgs) Handles ButtonMirror.Click

        Me.Invoke(Sub() Me.Visible = False)

    End Sub

End Class

考虑有关问题的这些事实:

  1. 当你在另一个线程中调用My.Forms.Main时,你得到的表单不是你在主线程中创建和显示的表单。这是 Main 的新实例。但是如果你在主线程中调用它,它就是创建其句柄的现有实例。 (My.Forms.Something 将return 主窗体的现有实例,对于其他窗体,创建一个新实例并缓存它并使用它。)

  2. 调用Invoke方法会抛出异常,如果窗体句柄没有创建,窗体句柄会在你展示后创建。

当你在另一个线程中调用My.Forms.Main.Invoke(Sub() My.Forms.Main.Visible = False)时,My.Forms.Main将是一个新的实例,并且它的句柄没有被创建,所以调用Invoke会导致你的异常收到。