怎么可能?我有Windows窗体控件,派生自System.Windows.Forms.Form,此窗体中包含WebBrowser控件。 Webbrowser对象实例是在form的构造函数中创建的(在InitializeComponent()方法中)。然后在后台线程中我使用WebBrowser的内容进行操作,我发现在某些情况下Form.InvokeRequired == false,而WebBrowser.InvokeRequired == true。怎么会这样?
答案 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;
(很抱歉在这个有点旧的帖子中发帖,但我只是觉得它对某人有用)。