可能"剥离"几个GUI线程? (不停止在Application.Run上的系统)

时间:2020-03-05 18:37:53  来源:igfitidea点击:

我的目标

我想要一个主处理线程(非GUI),并能够根据需要在其自己的后台线程中剥离GUI,并使我的主要非GUI线程继续工作。换句话说,我希望我的主要非GUI线程成为GUI线程的所有者,而不是相反。我不确定Windows Forms(?)甚至可能做到这一点

背景

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

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

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

  • 应用程序启动。
  • 检查配置文件中要加载的组件。加载它们。
  • 对于每个组件,运行DoStuff()对其进行初始化,并使它在自己的线程中过着自己的生活。
  • 永远继续做主要的应用程序-繁重的工作。

如果该组件在DoStuff()中启动了GUI,则我还无法成功执行第3点。它只是停止,直到关闭GUI。直到GUI关闭,程序才会前进到第4点。

如果允许这些组件启动自己的Windows Forms GUI,那将是非常不错的。

问题

当组件尝试在DoStuff()中启动GUI时(确切的代码行是当组件运行Application.Run(theForm)时),该组件及其系统因此"挂起"在Application上。运行()`行,直到关闭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()之后返回?

解决方案

回答

Application.Run方法显示一个(或者多个)表单并启动标准消息循环,该循环运行直到关闭所有表单为止。我们不能通过关闭所有表单或者强制关闭应用程序来强制从该方法返回。

但是,我们可以将ApplicationContext(新Form()的instad)传递给Application.Run方法,ApplicationContext可用于一次启动多个表单。仅当所有这些程序都关闭时,应用程序才会结束。参见此处:http://msdn.microsoft.com/zh-cn/library/system.windows.forms.application.run.aspx

另外,我们非模态显示的任何表单都将继续与主表单一起运行,这将使我们拥有不止一个相互阻塞的多个窗口。我相信这实际上是我们要实现的目标。

回答

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

" Windows"(我们在屏幕上看到的)与进程高度相关。也就是说,每个显示任何GUI的进程都应该有一个消息循环,该循环处理创建和管理窗口("单击按钮","关闭应用程序","重画屏幕"之类的所有消息)。 ' 等等。

因此,或者多或者少地假定如果我们有任何消息循环,则该消息循环在整个过程的生命周期中必须可用。例如,Windows可能会向我们发送"退出"消息,并且即使屏幕上没有任何内容,我们也需要有一个消息循环来处理该消息。

最好的选择是这样做:

制作一个永远不会显示的假表格,这是"主应用程序"
启动
调用Application.Run并通过此假表格传递。
在另一个线程中进行工作,并在需要执行Gui任务时在主线程中触发事件。

回答

我不确定这是否正确,但是我记得从控制台应用程序运行窗口表单,方法是仅更新表单并在其上调用newForm.Show(),如果组件使用该表单而不是Application.Run(),则新表格不应阻止。

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