2

在执行我的 win forms 应用程序时,我会得到一个跨线程异常,这似乎是一个随机的机会。这是我试图管理它的方式:

private void ToOutput(string s)
{
    if (!this.IsHandleCreated)
        this.CreateHandle();

    if (FormOutputArea.InvokeRequired)
    {
        FormOutputArea.Invoke(new Action(delegate ()
        {
            FormOutputArea.AppendText(s + Environment.NewLine);
        }));
    }
    else
    {
        FormOutputArea.AppendText(s + Environment.NewLine);
    }
}

它似乎InvokeRequired并不总是准确的。我尝试BeginInvoke了相同的结果。

编辑:即使我检查IsHandleCreatedInvokeRequired使用断点,它们也设置为 true,但else条件的分支仍被执行。

这是一个屏幕截图,显示了现在抛出异常的位置:

在此处输入图像描述

4

1 回答 1

5

将 CreateHandle() 和 InvokeRequired 放在同一个方法中是根本错误的。当尚未创建句柄时,这将爆炸,您将在错误的线程上创建本机窗口。子控件的窗口必须由拥有窗体的同一线程拥有,并且该线程必须泵送消息循环 (Application.Run)。

简单的解决方法是确保在创建窗体的窗口之前不会启动线程。这还将创建嵌入在该表单中的所有控件的窗口。最早发生在表单的 Load 事件中。此时,您可以相信 InvokeRequired 是准确的。

当用户关闭表单时要小心麻烦,如果您允许线程继续运行,您的原始代码将表现得非常糟糕。目前尚不清楚您是在创建窗体窗口之前还是在它关闭之后轰炸代码。您必须确保线程已停止或无法再调用 ToOutput()。这个答案的主题。

于 2013-09-14T15:10:42.670 回答