从控制台调用Form.Show()将冻结GUI [英] Form.Show() called from a console freezes the GUI

查看:71
本文介绍了从控制台调用Form.Show()将冻结GUI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图直接从控制台应用程序实例化表单.
出于某些奇怪的原因,当我调用 Form1.Show()时,新创建的Form不会绘制其所有控件并冻结(HourGlass图标).但是,当我调用ShowDialog()时,一切正常,除了我需要返回控制台,但我不能,所以这不是一个选择...
如何使表格正确显示?我在这里想念什么吗?

I am trying to instantiate a Form directly from a Console App.
For some weird reason, when I call Form1.Show() the newly created Form doesn't draw all its controls and Freezes (HourGlass icon). However, when I call ShowDialog(), everything goes fine, except that I need to go back to Console but I can't, so it is not an option...
What should I do to make my Form display correctly ? Am I missing something here ?

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

调用上述代码是为了响应控制台用户输入的命令.

The above code is called in response to a command entered by the Console user.

这是工作代码:

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

        mThread.SetApartmentState(ApartmentState.STA);

        mThread.Start();

我仍然不明白为什么我必须调用 ShowDialog()而不是 Show().
当我使用后者时,表单在绘制后立即消失".

I still don't see why I had to call ShowDialog() rather than Show().
When I use the latter the Form just "disappears" instantly after paint.

推荐答案

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

The reason is because ShowDialog performs its own message loop, whereas Show does not. Instead of calling Show, you would need to call Application.Run, which performs a message loop. However, since it synchronously loops, processing incoming window messages until the form is closed, it will be effectively no different than calling ShowDialog.

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

Therefore, if you want to show the form asynchronously, you would need to do so from another thread. However, just to be safe, make sure the new thread uses apartment threading by calling newThread.SetApartmentState(ApartmentState.STA);.

此外,我建议只显示一个UI线程中的一种主要形式.如果该主窗体从其自己的线程中显示其他窗体,那很好,但是,如果您开始尝试显示多个窗体,而每个窗体都从其自己的线程中出现,则可能会引起问题.

Also, I'd recommend only showing one main form from one UI thread. If that main form shows other forms from its own thread, that's fine, but, if you start trying to show multiple forms, each from their own thread, it can cause problems.

关于您的更新

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

The reason that calling Show from the thread does not work is two-fold. First, it is synchronous, so it does not return until the form is closed. That is important because as soon as execution leaves your anonymous method, the thread will terminate. So, when you call Show, it immediately returns, then leaves your method thereby terminating the thread.

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

Second, even if the form did stay open, it would be unresponsive, just as before, for all the same reasons. WinForms require a message loop that keeps looking for new incoming window messasges and processing them. The message loop calls a method called WndProc. Without a message loop calling the WndProc method to process the incoming window messages, the form will be totally unresponsive to users. For instance, when the mouse driver notifies windows that the user has pressed the mouse button, windows will then posts a WM_MOUSEDOWN message to your application's message queue. If you don't have code somewhere that is constantly looping looking to see if there are any messages in the queue and acting upon them, you'll never get the mouse down event.

如上所述, ShowDialog 方法执行其自身的消息循环,因此可以工作,但 Show 则无效. Show 假定它已由已运行的消息循环调用.如果由于某种原因您不想调用 ShowDialog ,则可以调用 Application.Run(StratControlBox). Run 方法将为您显示该表单,然后停留在消息循环中,直到关闭该表单.因此,这是一个同步调用,就像 ShowDialog 一样,因此您的线程直到窗体关闭后才会终止.

As I mentioned above, the ShowDialog method performs its own message loop, so it works, but Show does not. Show assumes that it is being called by an already running message loop. If for some reason you don't want to call ShowDialog, you can call Application.Run(StratControlBox), instead. The Run method will show the form for you and then stay in a message loop until the form is closed. Therefore, it is a synchronous call, just like ShowDialog, so your thread won't terminate until the form is closed.

这篇关于从控制台调用Form.Show()将冻结GUI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆