7

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

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

上面的代码是响应控制台用户输入的命令而调用的。

编辑: 这是工作代码:

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

        mThread.SetApartmentState(ApartmentState.STA);

        mThread.Start();

我仍然不明白为什么我必须打电话ShowDialog()而不是Show().
当我使用后者时,表格在绘画后立即“消失”。

4

3 回答 3

12

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

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

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

关于您的更新

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

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

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

于 2012-07-10T19:47:30.933 回答
4

我应该怎么做才能使我的表格正确显示?我在这里错过了什么吗?

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

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

于 2012-07-10T19:46:07.890 回答
-1

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

myForm.Show()

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

我已经在使用

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

因为其他一些要求。

于 2018-02-28T14:32:46.413 回答