我在Windows窗体中的跨线程调用有什么问题?

Ars*_*nko 9 c# multithreading invoke showdialog winforms

我遇到Windows窗体应用程序的问题.

必须从另一个线程显示表单.所以在表单类中,我有以下代码:

private delegate void DisplayDialogCallback();

public void DisplayDialog()
{
    if (this.InvokeRequired)
    {
        this.Invoke(new DisplayDialogCallback(DisplayDialog));
    }
    else
    {
        this.ShowDialog();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,每次我运行它时,InvalidOperationException都会抛出一条线this.ShowDialog();:

"跨线程操作无效:控制'SampleForm'从其创建的线程以外的线程访问."

这段代码有什么问题?这不是一种进行跨线程调用的有效方法吗?有什么特别的ShowDialog()吗?

SLa*_*aks 8

您可能在表单显示之前执行此代码.
因此,InvokeRequired正在回归false.


Jar*_*Par 5

我相信这里发生的事情是这个代码在Form显示之前就已经运行了.

Form在.Net中创建a时,它不会立即获得对特定线程的亲和力.只有在执行某些操作时,如显示它或抓住手柄才能获得亲和力.在此之前,很难InvokeRequired正常运作.

在这种特殊情况下,没有建立亲和关系并且不存在父控件,因此 InvokeRequired返回false,因为它无法确定原始线程.

解决此问题的方法是在UI线程上创建控件时建立关联.执行此操作的最佳方法是向控件询问其handle属性.

var notUsed = control.Handle;
Run Code Online (Sandbox Code Playgroud)


lor*_*ova 5

试试这个:

private delegate void DisplayDialogCallback();

public void DisplayDialog()
{
    if (this.InvokeRequired)
    {
        this.Invoke(new DisplayDialogCallback(DisplayDialog));
    }
    else
    {
        if (this.Handle != (IntPtr)0) // you can also use: this.IsHandleCreated
        {
            this.ShowDialog();

            if (this.CanFocus)
            {
                this.Focus();
            }
        }
        else
        {
            // Handle the error
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,InvokeRequired返回

如果控件的 Handle 是在与调用线程不同的线程上创建的,则为 true(表示您必须通过 invoke 方法调用控件);否则为假。

因此,如果尚未创建控件,则返回值将为false!