1

The application I am developing is a plugin to an existing application and the first time running the plugin everything works great. However when I open the plugin a second time I get the error:

InvalidOperationException was unhandled - Invoke or BeginInvoke cannot be called on a control until the window handle has been created.

I understand race conditions and from everything I've read, this error occurs when trying to access a form element before HandleCreated is true, but I cannot figure out why this is happening only the second time I open the plugin.

Here is the plugin code. The error occurs when calling SetProgressBar():

    private MainForm mainForm;

    public void StartPlugin()
    {
        mainForm  = new MainForm (this);
        mainForm .ShowDialog();
    }

    public bool GetJoinEnabled()
    {
        mainForm.SetProgressBar(3);
    }

Here's my main form:

    private Thread m_JoinThread;
    private JoinPlugin m_Join;

    public MainForm(JoinPlugin zig)
    {
        m_Join = zig;
        InitializeComponent();
        m_JoinThread= new Thread(new ThreadStart(GetJoinData));
        m_JoinThread.Start();
    }

    private void GetJoinData()
    {
       //Get enable join data
        bool result = m_Join.GetJoinEnabled();
    }

    public void SetProgressBar(int value)
    {
        SetProgressCallback del = new SetProgressCallback(SetProgressBarControl);
        this.Invoke(del, value);
    }

    private void SetProgressBarControl(int value)
    {
        progressBar.Value = value;
    }
McLovin
  • 1,455
  • 3
  • 19
  • 37
  • 1
    Does it happen if you add `mainForm.Dispose();` after `mainForm.ShowDialog();`? – keyboardP Jul 11 '13 at 21:06
  • it's strange that your `MainForm` becomes `ZigbeeJoinForm` in definition code? Unless your `MainForm` inherits `ZigbeeJoinForm`. – King King Jul 12 '13 at 03:03
  • `delegate` is a keyword which can't be used for variable name but this code line of yours is an exception? `SetProgressCallback delegate = new SetProgressCallback(SetProgressBarControl);` – King King Jul 12 '13 at 03:08
  • I think this code would fail right at the first time running, I can understand why it would fail but it's strange that you said it's OK for the first time running. – King King Jul 12 '13 at 03:10
  • @KingKing the delegate variable and ZigbeeJoinForm were mistakes when editing my question. I changed some of the naming around to make it easier to understand – McLovin Jul 12 '13 at 13:16
  • There's a clear race condition in the code, you start the thread too early. Not stopping the thread *before* the window is closed is also a serious problem. – Hans Passant Jul 12 '13 at 13:36
  • @HansPassant Is there a proper way to stop a thread before the window is closed? – McLovin Jul 12 '13 at 14:01
  • @keyboardP Yes it still happens. Joes answer below seems to be working. – McLovin Jul 12 '13 at 14:11
  • 1
    It is covered in [this question](http://stackoverflow.com/questions/1731384/how-to-stop-backgroundworker-on-forms-closing-event/1732361#1732361) – Hans Passant Jul 12 '13 at 14:13

1 Answers1

3

I'm guessing a little, but i ran into the same issue some time ago.

You are starting a thread in the forms constructor:

m_JoinThread.Start();

This starts the thread immediatedly and call Invoke somewhere. At this time, the form is not initilized completely.
Move the code to the Load event:

public ZigbeeJoinForm_Load()
{
    m_JoinThread= new Thread(new ThreadStart(GetJoinData));
    m_JoinThread.Start();
}

This ensures that the form is completely initialized and calling Invoke is safe then.

joe
  • 8,344
  • 9
  • 54
  • 80