以下是我正在尝试做的简化示例:
我有2个控件MyControl c
和Panel p
。 p
在主GUI线程中正常创建,但我希望在后台线程中创建c
,因为它需要一段时间,我不想冻结GUI。如何将c
添加到p.Controls
?如果我在this.Invoke
中执行此操作,则会为c
抛出异常,如果我从后台线程执行此操作,则会为p
抛出异常。
或者我真的不应该在主GUI线程之外创建GUI元素吗?
答案 0 :(得分:3)
或者我真的不应该在主GUI线程之外创建GUI元素吗?
是的,这基本上就是问题所在。大多数控件都具有线程关联性,必须在用户界面线程中创建。
通常,处理此问题的方法是将导致控件创建的“工作”移动到后台线程上,但仍然在UI线程上创建控件。然后,在慢速工作完成后,您可以使用Control.Invoke或Control.BeginInvoke更新UI中的信息。
例如,如果您从某个外部源加载一组数据,则可以创建该控件,并启动后台线程来加载数据。加载数据后,您可以然后更新控件以反映它。这将使它在整个时间内保持响应。
答案 1 :(得分:1)
可能是您的控件不需要很长时间来创建;相反,它需要很长时间才能获得数据。在这种情况下,请考虑创建一个可以在填充时显示UI的控件。然后,您可以在主线程中创建控件,在后台线程中填充它,并为您的用户提供更好的体验。
答案 2 :(得分:1)
使用后台线程执行它必须执行的操作,然后以某种方式发出信号(bool _backgroundCompleted
作为一个简单的示例)c
已准备好创建。
从c
创建Timer
,它会定期触发并在设置_backgroundCompleted
之前不执行任何操作,然后创建c
,然后终止计时器。
它可能是“丑陋的”,但它会起作用并且仍然很简单。
Forms.Timer
,如果你问;)
是的,永远不要在同一个表单上混淆多个线程。您可以在多个线程上拥有多个表单,但要执行此操作,您必须首先运行新线程,然后在其上创建表单。它将有自己的消息循环,并且会很好。