C# 可以“分拆”几个 GUI 线程吗?(不会在 Application.Run 停止系统)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2872/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Possible to "spin off" several GUI threads? (Not halting the system at Application.Run)
提问by andnil
My Goal
我的目标
I would like to have a main processing thread (non GUI), and be able to spin off GUIs in their own background threads as needed, and having my main non GUI thread keep working. Put another way, I want my main non GUI-thread to be the owner of the GUI-thread and not vice versa. I'm not sure this is even possible with Windows Forms(?)
我想要一个主处理线程(非 GUI),并且能够根据需要在自己的后台线程中分离 GUI,并且让我的主非 GUI 线程继续工作。换句话说,我希望我的主要非 GUI 线程成为 GUI 线程的所有者,反之亦然。我不确定 Windows 窗体(?)
Background
背景
I have a component based system in which a controller dynamically load assemblies and instantiates and run classes implementing a common IComponent
interface with a single method DoStuff()
.
我有一个基于组件的系统,其中控制器动态加载程序集并实例化和运行IComponent
使用单个方法实现公共接口的类DoStuff()
。
Which components that gets loaded is configured via a xml configuration file and by adding new assemblies containing different implementations of IComponent
. The components provides utility functions to the main application. While the main program is doing it's thing, e.g. controlling a nuclear plant, the components might be performing utility tasks (in their own threads), e.g. cleaning the database, sending emails, printing funny jokes on the printer, what have you. What I would like, is to have one of these components be able to display a GUI, e.g. with status information for the said email sending component.
加载哪些组件是通过 xml 配置文件配置的,并通过添加包含不同IComponent
. 这些组件为主应用程序提供实用功能。当主程序在做它的事情时,例如控制核电站,组件可能正在执行实用任务(在它们自己的线程中),例如清理数据库、发送电子邮件、在打印机上打印有趣的笑话,你有什么。我想要的是让这些组件之一能够显示 GUI,例如,带有所述电子邮件发送组件的状态信息。
The lifetime of the complete system looks like this
整个系统的生命周期是这样的
- Application starts.
- Check configuration file for components to load. Load them.
- For each component, run
DoStuff()
to initialize it and make it live its own life in their own threads. - Continue to do main application-thingy king of work, forever.
- 应用程序启动。
- 检查要加载的组件的配置文件。加载它们。
- 对于每个组件,运行
DoStuff()
以初始化它并使其在自己的线程中过自己的生活。 - 继续做主要的应用程序之王,永远。
I have not yet been able to successfully perform point 3 if the component fires up a GUI in DoStuff()
. It simply just halts until the GUI is closed. And not until the GUI is closed does the program progress to point 4.
如果组件在DoStuff()
. 它只是停止,直到 GUI 关闭。直到 GUI 关闭,程序才会进入第 4 点。
It would be great if these components were allowed to start up their own Windows Forms GUIs.
如果允许这些组件启动它们自己的 Windows 窗体 GUI,那就太好了。
Problem
问题
When a component tries to fire up a GUI in DoStuff()
(the exact line of code is when the component runs Application.Run(theForm)
), the component and hence our system "hangs" at the Application.Run()
line until the GUI is closed. Well, the just fired up GUI works fine, as expected.
当组件试图在其中启动 GUI 时DoStuff()
(确切的代码行是组件运行时Application.Run(theForm)
),组件以及我们的系统“挂起”在该Application.Run()
行,直到 GUI 关闭。好吧,正如预期的那样,刚刚启动的 GUI 工作正常。
Example of components. One hasn't nothing to do with GUI, whilst the second fires up a cute windows with pink fluffy bunnies in them.
组件示例。一个与 GUI 无关,而第二个则打开一个可爱的窗口,里面有粉红色的毛茸茸的兔子。
public class MyComponent1: IComponent
{
public string DoStuff(...) { // write something to the database }
}
public class MyComponent2: IComponent
{
public void DoStuff()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form());
// I want the thread to immediately return after the GUI
// is fired up, so that my main thread can continue to work.
}
}
I have tried this with no luck. Even when I try to fire up the GUI in it's own thread, the execution halts until the GUI as closed.
我试过这个没有运气。即使我尝试在它自己的线程中启动 GUI,执行也会停止,直到 GUI 关闭。
public void DoStuff()
{
new Thread(ThreadedInitialize).Start()
}
private void ThreadedInitialize()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form());
}
Is it possible to spin off a GUI and return after Application.Run()
?
是否可以剥离 GUI 并在之后返回Application.Run()
?
采纳答案by Ishmaeel
Application.Runmethod displays one (or more) forms and initiates the standard message loop which runs until all the forms are closed. You cannot force a return from that method except by closing all your forms or forcing an application shutdown.
Application.Run方法显示一个(或多个)表单并启动标准消息循环,该循环一直运行直到所有表单都关闭。您不能强制从该方法返回,除非关闭所有表单或强制关闭应用程序。
You can, however, pass an ApplicationContext(instad of a new Form()) to Application.Run method and ApplicationContext can be used to launch several forms at once. Your application will only end when all of those are closed. See here: http://msdn.microsoft.com/en-us/library/system.windows.forms.application.run.aspx
但是,您可以将ApplicationContext(新 Form() 的替代)传递给 Application.Run 方法,并且 ApplicationContext 可用于同时启动多个表单。只有当所有这些都关闭时,您的申请才会结束。请参阅此处:http: //msdn.microsoft.com/en-us/library/system.windows.forms.application.run.aspx
Also, any forms that you Show non-modally will continue to run alongside your main form, which will enable you to have more than one windows that do not block each other. I believe this is actually what you are trying to accomplish.
此外,您以非模态方式显示的任何表单将继续与主表单一起运行,这将使您拥有多个不会相互阻塞的窗口。我相信这实际上是你想要完成的。
回答by Orion Edwards
I'm sure this is possible if you hack at it hard enough, but I'd suggest it is not a good idea.
我敢肯定,如果你足够努力地破解它,这是可能的,但我建议这不是一个好主意。
'Windows' (that you see on the screen) are highly coupled to processes. That is, each process which displays any GUI is expected to have a Message Loop, which processes all of the messages which are involved with creating and managing windows (things like 'clicked the button', 'closed the app', 'redraw the screen' and so on.
“Windows”(您在屏幕上看到的)与进程高度耦合。也就是说,每个显示任何 GUI 的进程都应该有一个消息循环,它处理与创建和管理窗口有关的所有消息(例如“单击按钮”、“关闭应用程序”、“重绘屏幕” ' 等等。
Because of this, it is more or less assumed that if you have any message loop, it must be available for the lifetime of your process. For example windows might send you a 'quit' message, and you need to have a message loop available to handle that, even if you've got nothing on the screen.
因此,或多或少假设如果您有任何消息循环,它必须在您的进程的生命周期内可用。例如,Windows 可能会向您发送“退出”消息,您需要有一个消息循环来处理该消息,即使屏幕上没有任何内容。
Your best bet is do it like this:
你最好的选择是这样做:
Make a fake form which is never shown which is your 'main app' Start up Call Application.Run and pass in this fake form. Do your work in another thread, and fire events at the main thread when you need to do Gui stuff.
制作一个永远不会显示的假表单,哪个是您的“主应用程序” 启动调用 Application.Run 并传入这个假表单。在另一个线程中完成你的工作,当你需要做 Gui 的东西时,在主线程上触发事件。
回答by Sebastian Bender
I'm not sure if this is right, however I remember running window forms from a console application by just newing the form and calling newForm.Show() on it, if your components use that instead of Application.Run() then the new form shouldn't block.
我不确定这是否正确,但是我记得从控制台应用程序运行窗口表单,只需新建表单并在其上调用 newForm.Show(),如果您的组件使用它而不是 Application.Run() 那么新的表单不应该阻塞。
Of course the component will be responsible for maintaining a reference to the forms it creates
当然,组件将负责维护对其创建的表单的引用