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

Problem

In a WinForms project, if you try to call Invoke/BeginInvoke before the window handle is created, you’ll get the following exception:

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

Because this exception happens while the form is initializing, it typically results in the form not appearing at all. The only way to see the exception is by looking in Windows Event Viewer or running the project in a debugger.

Your code probably looks something like the code below. The important thing is that it’s calling BeginInvoke() from the constructor.

public partial class frmMain : Form { Control control; public frmMain() { InitializeComponent(); control = txtLog; Log("Initialized"); } private void Log(string msg) { control.BeginInvoke((MethodInvoker)delegate () { txtLog.AppendText(msg); txtLog.ScrollToCaret(); }); } }
Code language: C# (cs)

Solution

The error message is clear: you can’t call Invoke/BeginInvoke until the window handle is created. There are two ways to know when the window handle has been created:

  • The form event OnHandleCreated() has fired.
  • The this.IsHandleCreated property is true.

Therefore, there are two possible solutions. Take a look at the two options below.

Option 1 – Override OnHandleCreated() and move your code there

Most likely you actually intended on calling Invoke/BeginInvoke while the form is initializing.

The OnHandleCreated() event fires after the window handle has been created. You can only call Invoke/BeginInvoke after the window handle has been created. Therefore it makes sense to override OnHandleCreated() and call Invoke/BeginInvoke from there. This is the earliest possible time you can call Invoke/BeginInvoke.

public frmMain() { InitializeComponent(); control = txtLog; //Log("Initialized"); Don't call Invoke/BeginInvoke in the constructor } protected override void OnHandleCreated(EventArgs e) { base.OnHandleCreated(e); Log("Initialized"); } private void Log(string msg) { control.BeginInvoke((MethodInvoker)delegate () { txtLog.AppendText(msg); txtLog.ScrollToCaret(); }); }
Code language: C# (cs)

Option 2 – Check if the window handle is created before calling Invoke/BeginInvoke

On the rare chance that you simply want to get rid of the error message, you can simply check this.IsHandleCreated before calling Invoke/BeginInvoke.

public frmMain() { InitializeComponent(); control = txtLog; Log("Initialized"); } private void Log(string msg) { if (this.IsHandleCreated) { control.BeginInvoke((MethodInvoker)delegate () { txtLog.AppendText(msg); txtLog.ScrollToCaret(); }); } }
Code language: C# (cs)

2 thoughts on “WinForms – Invoke or BeginInvoke cannot be called on a control until the window handle has been created”

  1. I was using a Task.Factory.StartNew to get that error. It was not in the same form. It was easier for me to put a delay Thread.Sleep(500) in the action the StartNew was calling to give it a bit of time. The Action would pump in message in realtime to the form events – this form displayed the messages.

    Reply
    • That’s a nice way to deal with it in. So I’m assuming you can’t change the message form (third party code). If you could change the message form, I’d suggest using a queue and start processing the queue in the OnHandleCreated event.

      I reproduced your scenario with the following code (this is clarify things for other readers):

      var frm = new frmMessages();

      Task.Factory.StartNew(() =>
      {
        Thread.Sleep(500); //simple way to wait for the handle to be created

        frm.BeginInvoke((MethodInvoker)delegate ()
        {
          frm.Log("Help");
        });
      });
      frmMessages.ShowDialog();

      Note: To minimize sleep time, you could do a sleep loop – while(!frm.IsHandleCreated) (and cap the number of attempts) – but that’s probably an unnecessary optimization.

      Reply

Leave a Comment