我有以下Windows窗体代码:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
new Thread(SampleFunction).Start();
}
void SampleFunction()
{
for (int i = 0; i < 10; i++)
{
if (textBox1.InvokeRequired == true)
textBox1.Invoke((MethodInvoker)delegate { textBox1.Text += "HI. "; });
else
textBox1.Text += "HII. "; // Sometimes hit on first pass of the loop.
Thread.Sleep(1000);
}
}
当使用断点调试上面的代码时,我观察到第一次传递但是每10次运行只发生一次,就会触发非调用所需的路径。我很惊讶,因为代码是在一个单独的线程上,我希望InvokeRequired
始终是真的。有人可以放光吗?
答案 0 :(得分:1)
很可能是因为你在表单的构造函数中启动线程。此时表单尚未显示,并且在执行第一次迭代时可能尚未创建其窗口句柄。
来自MSDN:
如果控件的句柄尚不存在,InvokeRequired将向上搜索控件的父链,直到找到具有窗口句柄的控件或表单。如果找不到合适的句柄,InvokeRequired方法将返回 false 。
[...]
一种解决方案是在启动后台线程之前等待表单的句柄创建。通过调用Handle属性强制创建句柄,或者等到Load事件开始后台进程。
所以我看到你有两种选择。 1)请等待,直到检查IsHandleCreated
property:
for (int i = 0; i < 10; i++)
{
while (!this.IsHandleCreated) { Thread.Sleep(25); }
...
}
2)检查Handle
属性以强制创建窗口句柄(我将其放在while
循环中以防万一):
for (int i = 0; i < 10; i++)
{
while (this.Handle == IntPtr.Zero) { Thread.Sleep(25); }
...
}
如您所见,我访问this
而不是textBox1
。我建议你在检查和调用时也这样做,因为Control.Invoke()
无论如何都会查找绝对父(表单)。