我有一个函数,它向父控件添加一个控件,该控件从与创建控件的线程不同的线程调用。这是怎么回事:
1 delegate void AddControlToParentDelegate(Control child, Control parent);
2 private void addControlToParent(Control child, Control parent) {
3 if (parent.InvokeRequired) {
4 AddControlToParentDelegate d = new AddControlToParentDelegate(addControlToParent);
5 this.Invoke(d, new object[] { child, parent });
6 } else {
7 parent.Controls.Add(child);
8 }
9 }
10 }
这可以正常工作,直到parent.InvokeRequired
和child.InvokeRequired
都为TRUE。然后,一旦执行第5行(现在调用委托d
并且该函数应该在UI线程上运行。(对吗?))第7行的child
抛出一个跨线程操作无效的例外。为什么是这样?它已经在它创建的线程上运行了吗?
我设法通过添加额外的(child.InvokeRequired)
支票来解决此问题:
delegate void AddControlToParentDelegate(Control child, Control parent);
private void addControlToParent(Control child, Control parent) {
if (parent.InvokeRequired) {
AddControlToParentDelegate d = new AddControlToParentDelegate(addControlToParent);
this.Invoke(d, new object[] { child, parent });
} else {
if (child.InvokeRequired) {
this.Invoke(new MethodInvoker(delegate() {
parent.Controls.Add(child);
}));
} else {
parent.Controls.Add(child);
}
}
}
但这看起来非常糟糕且不必要。这是这样做的吗?或者我完全错过了公共汽车?
答案 0 :(得分:6)
请注意,当控件没有窗口句柄时,InvokeRequired不可靠。对于新创建的没有父级的子控件几乎肯定会出现这种情况,这似乎是“固定”代码中的情况。
见Ivan Krivyakov的详细分析:http://www.ikriv.com/en/prog/info/dotnet/MysteriousHang.html