26

我的目标

我想要一个主处理线程(非 GUI),并且能够根据需要在自己的后台线程中分离 GUI,并让我的主非 GUI 线程继续工作。换句话说,我希望我的主要非 GUI 线程成为 GUI 线程的所有者,反之亦然。我不确定这甚至可以使用 Windows 窗体(?)

背景

我有一个基于组件的系统,其中控制器动态加载程序集并实例化和运行实现IComponent具有单个方法的通用接口的类DoStuff()

加载哪些组件是通过 xml 配置文件和添加包含不同实现的新程序集来配置的IComponent。组件向主应用程序提供实用功能。虽然主程序正在做它的事情,例如控制核电站,但组件可能正在执行实用任务(在它们自己的线程中),例如清理数据库,发送电子邮件,在打印机上打印有趣的笑话,你有什么。我想要的是让这些组件中的一个能够显示 GUI,例如带有所述电子邮件发送组件的状态信息。

整个系统的生命周期是这样的

  1. 应用程序启动。
  2. 检查配置文件以加载要加载的组件。加载它们。
  3. 对于每个组件,运行DoStuff()以对其进行初始化,并使其在自己的线程中过上自己的生活。
  4. 继续做主要的应用程序,永远的工作之王。

如果组件在DoStuff(). 它只是停止,直到 GUI 关闭。直到关闭 GUI,程序才会进入第 4 点。

如果允许这些组件启动它们自己的 Windows 窗体 GUI,那就太好了。

问题

当组件尝试在其中启动 GUI 时DoStuff()(确切的代码行是组件运行时Application.Run(theForm)),组件以及因此我们的系统在该行“挂起”,Application.Run()直到 GUI 关闭。好吧,正如预期的那样,刚刚启动的 GUI 工作正常。

组件示例。一个与 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.
    }
}

我试过这个没有运气。即使我尝试在它自己的线程中启动 GUI,执行也会停止,直到 GUI 关闭。

public void DoStuff()
{
    new Thread(ThreadedInitialize).Start()
}

private void ThreadedInitialize()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new Form());
}

是否可以分拆 GUI 并在之后返回Application.Run()

4

3 回答 3

13

Application.Run方法显示一个(或多个)表单并启动标准消息循环,该循环一直运行直到所有表单关闭。除了关闭所有表单或强制关闭应用程序外,您不能强制从该方法返回。

但是,您可以将ApplicationContext(代替新的 Form())传递给 Application.Run 方法,并且 ApplicationContext 可用于一次启动多个表单。只有当所有这些都关闭时,您的申请才会结束。见这里:http: //msdn.microsoft.com/en-us/library/system.windows.forms.application.run.aspx

此外,您以非模态方式显示的任何表单都将继续与您的主表单一起运行,这将使您能够拥有多个不会相互阻塞的窗口。我相信这实际上是你想要完成的。

于 2008-08-05T21:45:17.663 回答
0

我敢肯定,如果您足够努力地破解它,这是可能的,但我认为这不是一个好主意。

“Windows”(您在屏幕上看到的)与进程高度耦合。也就是说,显示任何 GUI 的每个进程都应该有一个消息循环,它处理与创建和管理窗口有关的所有消息(例如“单击按钮”、“关闭应用程序”、“重绘屏幕' 等等。

因此,或多或少假设如果您有任何消息循环,它必须在您的进程的生命周期内可用。例如,windows 可能会向您发送一条“退出”消息,并且您需要有一个消息循环来处理它,即使您在屏幕上什么也没有。

你最好的选择是这样做:

制作一个从未显示的假表格,它是您的“主应用程序”启动呼叫 Application.Run 并传入这个假表格。在另一个线程中做你的工作,当你需要做 Gui 的东西时在主线程上触发事件。

于 2008-08-05T23:22:00.743 回答
0

我不确定这是否正确,但是我记得通过新建表单并在其上调用 newForm.Show() 来从控制台应用程序运行窗口表单,如果您的组件使用它而不是 Application.Run() 那么新的表格不应该阻塞。

当然,组件将负责维护对其创建的表单的引用

于 2009-05-23T21:57:11.120 回答