Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's wrong with my cross-thread call in Windows Forms?

I encounter a problem with a Windows Forms application.

A form must be displayed from another thread. So in the form class, I have the following code:

private delegate void DisplayDialogCallback();

public void DisplayDialog()
{
    if (this.InvokeRequired)
    {
        this.Invoke(new DisplayDialogCallback(DisplayDialog));
    }
    else
    {
        this.ShowDialog();
    }
}

Now, every time I run this, an InvalidOperationException is thrown on the line this.ShowDialog();:

"Cross-thread operation not valid: Control 'SampleForm' accessed from a thread other than the thread it was created on."

What's wrong with this piece of code? Isn't it a valid way to make cross-thread calls? Is there something special with ShowDialog()?

like image 849
Arseni Mourzenko Avatar asked Jun 15 '10 14:06

Arseni Mourzenko


People also ask

What is CheckForIllegalCrossThreadCalls?

CheckForIllegalCrossThreadCalls parameter. The BlueZone ActiveX control is a legacy control that was developed before . NET. It has functionality that will hook into the container window's message processing to intercept messages. Messages received are passed back to .

What is InvokeRequired in C#?

Gets a value indicating whether the caller must call an invoke method when making method calls to the control because the caller is on a different thread than the one the control was created on. public: property bool InvokeRequired { bool get(); }; C# Copy.


2 Answers

You are likely getting to this code before the form has been shown and therefore the window handle has not been created.

You can add this code before your code and all should be good:

if (! this.IsHandleCreated)
   this.CreateHandle();

Edit: There's another problem with your code. Once the form is displayed, you cannot call ShowDialog() again. You will get an invalid operation exception. You may want to modify this method as others have proposed.

You might be better served calling the ShowDialog() directly from the calling class and have another method for BringToFront() or something like that...

like image 136
Scott P Avatar answered Nov 15 '22 17:11

Scott P


You could always try testing against a different control.

For example, you could access Application.Forms collections

public Control GetControlToInvokeAgainst()
{
    if(Application.Forms.Count > 0)
    {
        return Application.Forms[0];
    }
    return null;
}

Then in your DisplayDialog() method, call the GetControlToInvokeAgainst() and test for null before trying to perform an invokerequired call.

like image 32
Ben Cawley Avatar answered Nov 15 '22 16:11

Ben Cawley