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

Meh*_*ANI 6 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();
Run Code Online (Sandbox Code Playgroud)

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

编辑: 这是工作代码:

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

        mThread.SetApartmentState(ApartmentState.STA);

        mThread.Start();
Run Code Online (Sandbox Code Playgroud)

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

Ste*_*art 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,所以你的线程将不会终止,直到窗体关闭.

  • @MikaJacobi跨线程错误消息是因为您尝试从非UI线程访问UI对象.您需要调用`Control.Invoke`(阻塞)或`Control.BeginInvoke`(非阻塞)来执行UI线程上的代码(然后可以访问UI元素的代码).顺便说一句`Form`是一个`Control`(也就是它包含那些方法). (2认同)