这怎么可能呢?我有windows窗体控件,它是从System.Windows.Forms.Form派生的,在这个窗体中包含WebBrowser控件。Webbrowser对象实例在form的构造函数中创建(在InitializeComponent()方法中)。然后在后台线程中,我操纵WebBrowser的内容,我发现在某些情况下Form.InvokeRequired ==为假,而WebBrowser.InvokeRequired ==为真。怎么会这样呢?
发布于 2010-10-25 20:23:09
在显示表单之前,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。
这意味着,如果不需要Invoke (调用发生在同一线程上),或者如果控件是在另一个线程上创建的但控件的句柄尚未创建,则InvokeRequired可能会返回false。
如果控件的句柄尚未创建,则不应简单地调用控件上的属性、方法或事件。这可能会导致在后台线程上创建控件的句柄,从而在没有消息泵的线程上隔离控件,并使应用程序不稳定。
当InvokeRequired在后台线程上返回false时,还可以检查IsHandleCreated的值,以防止出现这种情况。如果尚未创建控件句柄,则必须等到创建后再调用Invoke或BeginInvoke。通常,只有在显示窗体或调用Application.Run之前,在应用程序的主窗体的构造函数中创建了后台线程(如Application.Run(new MainForm(),才会发生这种情况。
您的解决方案是也检查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: False这个: False
button1: True this: False
发布于 2010-10-26 03:53:19
下面是对相应的、更通用的问题的详细调查:http://www.ikriv.com/en/prog/info/dotnet/MysteriousHang.html
发布于 2011-02-17 18:28:16
我一直在调查同样的怪异行为。我需要从不同的线程操作一些控件(例如,显示连接到主机的设备的信息,或者根据不同的设备状态触发操作)。
这个链接给了我一个很好的提示: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;(很抱歉在这篇有点老的帖子中发表了这篇文章,但我只是认为它可能对某些人有用)。
https://stackoverflow.com/questions/4013954
复制相似问题