Form == false的InvokeRequired和包含控件的InvokeRequired == true

Dmi*_*nov 7 .net webbrowser-control invokerequired winforms

这怎么可能?我有Windows窗体控件,派生自System.Windows.Forms.Form,此窗体中包含WebBrowser控件.Webbrowser对象实例是在form的构造函数中创建的(在InitializeComponent()方法中).然后在后台线程中我使用WebBrowser的内容进行操作,我发现在某些情况下Form.InvokeRequired == false,而WebBrowser.InvokeRequired == true.怎么会这样?

Alb*_*nbo 9

Form.InvokeRequiredfalse在显示表单之前返回.

我做了一个简单的测试:

Form2 f2 = new Form2();
Thread t = new Thread(new ThreadStart(() => PrintInvokeRequired(f2)));
t.Start();
t.Join();

f2.Show();

t = new Thread(new ThreadStart(() => PrintInvokeRequired(f2)));
t.Start();
t.Join();
Run Code Online (Sandbox Code Playgroud)

与帮助者

private void PrintInvokeRequired(Form form)
{
    Console.WriteLine("IsHandleCreated: " + form.IsHandleCreated + ", InvokeRequired: " + form.InvokeRequired);
}
Run Code Online (Sandbox Code Playgroud)

输出是

IsHandleCreated:False,InvokeRequired:False
IsHandleCreated:True,InvokeRequired:True

另请注意,这在MSDN上有所记录:

如果控件的句柄尚不存在,InvokeRequired将向上搜索控件的父链,直到找到具有窗口句柄的控件或表单.如果找不到合适的句柄,则InvokeRequired方法返回false.

这意味着如果不需要Invoke(调用发生在同一个线程上),或者控件是在另一个线程上创建但尚未创建控件的句柄,则InvokeRequired可以返回false.

如果尚未创建控件的句柄,则不应简单地在控件上调用属性,方法或事件.这可能导致在后台线程上创建控件的句柄,在没有消息泵的情况下隔离线程上的控件并使应用程序不稳定.

当InvokeRequired在后台线程上返回false时,还可以通过检查IsHandleCreated的值来防止这种情况.如果尚未创建控件句柄,则必须等到创建它之后再调用Invoke或BeginInvoke.通常,只有在应用程序的主要表单的构造函数中创建后台线程(如在Application.Run(new MainForm())中,在显示表单或调用Application.Run之前,才会发生这种情况.

你的解决方案是检查IsHandleCreated.

编辑:
Handle可以在任何时间在浏览器控件或外部内部创建.这不会自动创建父窗体的句柄.

我创建了一个例子:

public Form2()
{
    InitializeComponent();

    Button button1 = new Button();
    this.Controls.Add(button1);

    Console.WriteLine("button1: " + button1.IsHandleCreated + " this: " + this.IsHandleCreated);
    var tmp = button1.Handle; // Forces the Handle to be created.
    Console.WriteLine("button1: " + button1.IsHandleCreated + " this: " + this.IsHandleCreated);
}
Run Code Online (Sandbox Code Playgroud)

与输出:

button1:False this:False
button1:True this:False