1

我有以下 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始终如此。有人可以阐明吗?

4

1 回答 1

1

这很可能是因为您在表单的构造函数中启动了线程。此时表单尚未显示,并且在执行第一次迭代时可能尚未创建其窗口句柄。

MSDN

如果控件的句柄尚不存在,InvokeRequired 将向上搜索控件的父链,直到找到具有窗口句柄的控件或窗体。如果找不到合适的句柄,则 InvokeRequired 方法返回false

[...]

一种解决方案是等到创建了表单的句柄后再启动后台线程。通过调用 Handle 属性强制创建句柄,或者等到 Load 事件启动后台进程。

所以在我看来,你有两个选择。1)等到通过检查IsHandleCreated属性创建句柄:

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

    ...
}

As you see I access this rather than textBox1. I recommend you to do this when checking and invoking as well because Control.Invoke() will lookup the absolute parent (the form) anyway.

于 2017-03-11T21:18:58.643 回答