Close a form from an external thread using the Invoke method

13,777

Solution 1

Use this method :

// Inspired from: http://stackoverflow.com/a/12179408/1529139
public static void InvokeIfRequired(Control control, MethodInvoker action)
{
    if (control.IsDisposed)
    {
        return;
    }

    if (control.InvokeRequired)
    {
        try
        {
            control.Invoke(action);
        }
        catch (ObjectDisposedException) { }
        catch (InvalidOperationException e)
        {
            // Intercept only invokation errors (a bit tricky)
            if (!e.Message.Contains("Invoke"))
            {
                throw e;
            }
        }
    }
    else
    {
        action();
    }
}

Usage example:

Functions.InvokeIfRequired(anyControl, (MethodInvoker)delegate()
{
    // UI stuffs
});

Solution 2

So far the best solution for this case has been to use the SynchronizationContext mechanism. I had the tip in Should I use Invoke or SynchronizationContext to update form controls from another thread?.

The example code would be like this:

private void Form1_Load(object sender, EventArgs e)
{
    Thread thread = new Thread(MethodThread);
    thread.Start(SynchronizationContext.Current);
}

private void MethodThread(Object syncronizationContext)
{
    ((SynchronizationContext)syncronizationContext).Send(CloseForm,null);
}

private void CloseForm(Object state)
{
    Close();
}
Share:
13,777
Alfort
Author by

Alfort

Updated on August 21, 2022

Comments

  • Alfort
    Alfort over 1 year

    I have to close a Form from a thread and I am using the Invoke method of the Form for calling the Close() method.

    The problem is that when closing, the form is disposed and I get an InvalidOperationExecption wit the message "Invoke or BeginInvoke cannot be called on a control until the window handle has been created.".

    I have got this exception only when debugging with a "Step Into" in the Close method but I don't want to risk with a possible error on normal running.

    This is an example code to reproduce it:

     private void Form1_Load(object sender, EventArgs e)
     {
         Thread thread = new Thread(CloseForm);
         thread.Start();
     }
    
     private void CloseForm()
     {
         this.Invoke(new EventHandler(
             delegate
             {
                 Close(); // Entering with a "Step Into" here it crashes.
             } 
         ));
     }
    

    The form is disposed in the automatic generated code for the form (which I would like not to modify):

        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
    

    I would appreciate it if someone could give me a solution for this or another way to close a form from another thread.

  • Alfort
    Alfort about 12 years
    Thanks for your answer. Maybe I didn't put an easy example. My code is of course different.I believe that the load event is created after the handle of the form is created but anyway the error is still there and with your example code the exception is also raised.