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

时间:2010-10-25 11:07:42

标签: .net winforms webbrowser-control invokerequired

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

3 个答案:

答案 0 :(得分:9)

Form.InvokeRequired在显示表单之前返回false

我做了一个简单的测试:

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();

与助手

private void PrintInvokeRequired(Form form)
{
    Console.WriteLine("IsHandleCreated: " + form.IsHandleCreated + ", InvokeRequired: " + form.InvokeRequired);
}

输出

  

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

另请注意,MSDN

会对此进行详细记录
  

如果控件的手柄还没有   现在,InvokeRequired搜索了   控制的父链直到找到   控件或表格确实有   窗把手。如果不合适   手柄可以找到,   InvokeRequired方法返回false。

     

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

     

在控件的句柄中   尚未创建,你应该   不是简单地调用属性,方法,   或控件上的事件。这有可能   导致控件的句柄   在后台线程上创建,   隔离线程上的控件   没有消息泵和制作   应用不稳定。

     

您可以通过以下方式防范此情况   还要检查的价值   InvokeRequired时IsHandleCreated   在后台线程上返回false。   如果还没有控制手柄   创建,你必须等到它   在调用Invoke之前创建的   BeginInvoke的。通常,这会发生   仅在创建后台线程时   在主窗体的构造函数中   对于应用程序(如在   Application.Run(new MainForm()),   在表格显示之前或   已经调用了Application.Run。

您的解决方案是检查IsHandleCreated

修改
可以在WebBrowser控件内部的任何时间或外部创建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);
}

输出:

  

button1:错误:错误   button1:如果:False

答案 1 :(得分:1)

以下是对相应且更通用的问题的详细调查:http://www.ikriv.com/en/prog/info/dotnet/MysteriousHang.html

答案 2 :(得分:0)

我一直在研究这种奇怪的行为。 我需要从不同的线程操作一些控件(例如,显示有关连接到主机的设备的信息或根据不同的设备状态触发操作)。

此链接给了我一个很好的提示: http://csharpfeeds.com/post/2898/Control.Trifecta_InvokeRequired_IsHandleCreated_and_IsDisposed.aspx

我仍然不知道MS人们打算如何利用他们自己的东西(并且在许多方面都不同意),但是,在一个应用程序中,我不得不做出以下肮脏和污秽的解决方法:

  • 在主线程中创建控件/表单(确保它是主线程)。
  • 在同一程序中,检查控制手柄。这个简单的检查将强制在正确的线程中创建

多么难看,不是吗? 我想知道是否有其他人有更好的方法来做到这一点。

_my_control = new ControlClass( );
_my_control.Owner = this;

IntPtr hnd;

// Force Handle creation by reading it.
if ( !_my_control.IsHandleCreated || _my_control.Handle == IntPtr.Zero )
    hnd = _my_control.Handle;

(很抱歉在这个有点旧的帖子中发帖,但我只是觉得它对某人有用)。