I'm new to C# and async programming so the solution to the problem I have might be simple (or not?!).
Here is the issue:
"Invoke or BeginInvoke cannot be called on a control until the window handle has been created".
private async void btnNewTab_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Multiselect = true;
openFileDialog.Filter = "*.test";
DialogResult dialogResult = openFileDialog.ShowDialog();
if (dialogResult == DialogResult.OK)
{
//Display a basic loading Control while the other control is being prepared
TabPage myTabPage = new TabPage("loading");
LoadingControlPanel loadingPanel = new LoadingControlPanel();
loadingPanel.Dock = DockStyle.Fill;
myTabPage.Controls.Add(loadingPanel);
tabControl.TabPages.Add(myTabPage);
tabControl.SelectTab(myTabPage);
//Load Data from files
List<DataFile> result = await Task.Run(() => loadFiles(openFileDialog.FileNames));
// create Control to display the data loaded
MyTabControl newPanel = new MyTabControl();
newPanel.Dock = DockStyle.Fill;
// provide Data to new control (long processing)
await Task.Run(() => newPanel.processData(result));
// rename Tab, remove loading Control and display the tab with the processed Data
myTabPage.Text = "Loaded";
myTabPage.Controls.Remove(loadingPanel);
myTabPage.Controls.Add(newPanel);
}
}
The crash always happen while I call the function "processData" but not alway at the same location. I have a few debug lines and they are not always the same processed.
The crash tells me the issue in on the line: "Application.Run(new FormMain());"
static void Main()
{
Application.SetHighDpiMode(HighDpiMode.SystemAware);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new FormMain());
}
Here is the full stack trace:
System.Reflection.TargetInvocationException HResult=0x80131604
Message=Exception has been thrown by the target of an invocation.
Source=System.Private.CoreLib StackTrace: at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Delegate.DynamicInvokeImpl(Object[] args) at System.Delegate.DynamicInvoke(Object[] args) at System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry tme) at System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(Object obj) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) --- End of stack trace from previous location --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry tme) at System.Windows.Forms.Control.InvokeMarshaledCallbacks()
at System.Windows.Forms.Control.WndProc(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, WM msg, IntPtr wparam, IntPtr lparam) at Interop.User32.DispatchMessageW(MSG& msg) at System.Windows.Forms.Application.ComponentManager.Interop.Mso.IMsoComponentManager.FPushMessageLoop(UIntPtr dwComponentID, msoloop uReason, Void* pvLoopData) at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(msoloop reason, ApplicationContext context) at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(msoloop reason, ApplicationContext context) at System.Windows.Forms.Application.Run(Form mainForm) at Program.Main() in Program.cs:line 22This exception was originally thrown at this call stack: [External Code]
Inner Exception 1: InvalidOperationException: Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
What on earth am I doing wrong with all this?
The heart of the issue I had is that creating a Control will not automatically ensure the handler connected to it is created.
I changed my code to display the panel first (with a loading message) while the data is processed and displayed asynchronously.
As pointed by @Henk Holterman, the architecture can/should be changed and improved to avoid the need for this solution.