In specific asynchronous circumstances I'm getting a System.Reflection.TargetInvocationException
exception with this error message:
Invoke or BeginInvoke cannot be called on a control until the window handle has been created
Please note that THIS IS NOT A DUPLICATE QUESTION, here below I explain why. I am aware of what the error means, but that exception cannot be/should not be thrown, because the handle of the window is created in my code.
I'm starting to think this error message I'm getting could be a new bug in the .NET Framework, I need the help of someone that could clarify whether it is my fault in the code or not my fault, and how to fix this problem.
I just have this class that represents the main application Form:
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
Note that the event-handler has the Async
keyword specified.
And this is the BuildMirror
method
Friend NotInheritable Class MirrorUtil
Friend Shared Function BuildMirror() As Boolean
My.Forms.Main.Invoke(Sub() My.Forms.Main.Visible = False)
End Function
End Class
The problem is inside the block of the BuildMirror
method, and ONLY happens if I call it asynchronously like I'm doing in the code above, the Main.Invoke()
method throws the exception mentioned, and if I perform a call to Main.IsHandleCreated
it surprisingly returns False
! ...only when I call asynchronously the BuildMirror
method, I insist.
I would like to understand what is happening, and how to fix it. Of course the main application form is instanced and visible, the window handle is created, then it should not throw that exception...
I found this strange issue while trying to debug the real problem, which is not the problem that I exposed in this question, however I think this strange problem is the cause of my real problem, so I would appreciate a solution for this.
Consider these facts about the problem:
When you call My.Forms.Main
in another thread, the form which you get, is not the form which you created and showed in the main thread. It's a new instance of Main
. But if you call it in the main thread, it's the existing instance which its handle is created. (My.Forms.Something
will return the existing instance for the main form, and for other forms, create a new instance and cache it and use it.)
Calling Invoke
method will throw an exception, if the handle of the form is not created and the handle of the form will be created after you show it.
When you call My.Forms.Main.Invoke(Sub() My.Forms.Main.Visible = False)
in another thread, My.Forms.Main
will be a new instance, and it's handle is not created, so calling Invoke
on it will result the exception which you received.