从控制台调用的Form.Show()冻结了GUI

时间:2012-07-10 19:43:17

标签: c# winforms

我正在尝试直接从控制台应用程序实例化一个表单 出于一些奇怪的原因,当我调用Form1.Show()时,新创建的Form不会绘制其所有控件和冻结(HourGlass图标)。但是,当我调用ShowDialog()时,一切都很顺利,除了我需要回到控制台,但我不能,所以它不是一个选项...
我该怎么做才能正确显示表格?我在这里错过了什么吗?

OrderControlForm OrderControlBox = new OrderControlForm();
OrderControlBox.BuyEvent += new OrderControl.BuyDelegate(doBuy);
OrderControlBox.SellEvent += new OrderControl.SellDelegate(doSell);
OrderControlBox.Show();

调用上述代码以响应Console用户输入的命令。

编辑: 这是工作代码:

        Thread mThread = new Thread(delegate()
        {
            StratControlBox = new StratControl(StratIDs);
            StratControlBox.ShowDialog();
        });

        mThread.SetApartmentState(ApartmentState.STA);

        mThread.Start();

我仍然不明白为什么我不得不拨打ShowDialog()而不是Show() 当我使用后者时,Form在涂漆后立即“消失”。

3 个答案:

答案 0 :(得分:10)

原因是ShowDialog执行自己的消息循环,而Show没有。您需要调用Show来执行消息循环,而不是调用Application.Run。但是,由于它同步循环,处理传入的窗口消息直到窗体关闭,它实际上与调用ShowDialog没有什么不同。

因此,如果要以异步方式显示表单,则需要从另一个线程执行此操作。但是,为了安全起见,请确保新线程通过调用newThread.SetApartmentState(ApartmentState.STA);来使用公寓线程。

另外,我建议只显示一个UI线程中的一个主窗体。如果那个主窗体显示其自己的线程中的其他窗体,那很好,但是,如果你开始尝试显示多个窗体,每个窗体都来自它们自己的线程,它可能会导致问题。

关于您的更新

从线程调用Show不起作用的原因是双重的。首先,它是同步的,因此在表单关闭之前它不会返回。这很重要,因为只要执行离开您的匿名方法,线程就会终止。因此,当您调用Show时,它会立即返回,然后离开您的方法,从而终止该线程。

其次,即使表格确实保持开放,但由于所有相同的原因,它也会像以前一样反应迟钝。 WinForms需要一个消息循环,不断寻找新的传入窗口消息并处理它们。消息循环调用名为WndProc的方法。如果没有消息循环调用WndProc方法来处理传入的窗口消息,则表单将完全不响应用户。例如,当鼠标驱动程序通知窗口用户已按下鼠标按钮时,窗口将向您的应用程序的消息队列发送WM_MOUSEDOWN消息。如果你没有代码在某个地方不断循环查看队列中是否有任何消息并对其采取行动,那么你永远不会得到鼠标按下事件。

正如我上面提到的,ShowDialog方法执行自己的消息循环,因此它可以工作,但Show没有。 Show假定它已被正在运行的消息循环调用。如果由于某种原因您不想拨打ShowDialog,则可以拨打Application.Run(StratControlBox)Run方法将为您显示表单,然后保留在消息循环中,直到表单关闭。因此,它是一个同步调用,就像ShowDialog一样,因此在表单关闭之前,您的线程不会终止。

答案 1 :(得分:3)

  

如何正确显示表单?我在这里错过了什么吗?

问题是控制台应用程序不是Windows应用程序,并且没有适当的“管道”来处理Windows消息。如果没有这个,表单就无法正确处理项目,包括“绘制”等基本信息。

通过使用Application.Run启动消息处理,可以正常处理。但是,这会阻塞,直到表单关闭(因此控制台不会继续“运行”)。处理此问题的方法是将控制台代码移动到单独的线程中,并将Application.Run与您的表单一起使用,就像普通的Windows应用程序一样。

答案 2 :(得分:-1)

在.NET 4.7中,我能够简单地改变

myForm.Show()

Task.Run(() => { myForm.ShowDialog(); });

我已经在使用

[STAThread] 
private static void Main(string[] args)
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    .
    .
    .
}

因为其他一些要求。