可以“分拆”几个 GUI 线程吗?(不在 Application.Run 处停止系统)

StackOverflow https://stackoverflow.com/questions/2872

  •  08-06-2019
  •  | 
  •  

我的目标

我希望有一个主处理线程(非 GUI),并且能够根据需要在自己的后台线程中分离 GUI,并让我的主非 GUI 线程继续工作。换句话说,我希望我的主要非 GUI 线程成为 GUI 线程的所有者,而不是相反。我不确定这对于 Windows 窗体是否可行(?)

背景

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

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

整个系统的生命周期如下所示

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

如果组件在以下位置启动 GUI,我还无法成功执行第 3 点 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 时,执行也会停止,直到 GUI 关闭。

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

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

是否可以剥离 GUI 并在之后返回 Application.Run()?

有帮助吗?

解决方案

应用程序.运行 方法显示一个(或多个)表单并启动标准消息循环,该循环运行直到所有表单都关闭。除非关闭所有表单或强制关闭应用程序,否则无法强制从该方法返回。

但是,您可以通过 应用上下文 (而不是新的 Form())到 Application.Run 方法和 ApplicationContext 可用于一次启动多个表单。只有当所有这些都关闭时,您的申请才会结束。看这里: http://msdn.microsoft.com/en-us/library/system.windows.forms.application.run.aspx

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

其他提示

我确信如果你足够努力的话这是可能的,但我建议这不是一个好主意。

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

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

你最好的选择是这样做:

制作一个从未显示的伪造表单,这是您的“主要应用程序”启动呼叫应用程序。在另一个线程中完成工作,并在需要执行 Gui 操作时在主线程中触发事件。

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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top