代码之家  ›  专栏  ›  技术社区  ›  andynil

可以“分拆”几个GUI线程吗?(在application.run时不停止系统)

  •  20
  • andynil  · 技术社区  · 16 年前

    我的目标

    我希望有一个主处理线程(非图形用户界面),并且能够根据需要在自己的后台线程中剥离图形用户界面,并且让我的主非图形用户界面线程继续工作。换句话说,我希望我的主要非GUI线程是GUI线程的所有者,反之亦然。我不确定这在Windows窗体(?)中是否可行。

    背景

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

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

    整个系统的生命周期如下

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

    如果组件在 doSuffor() . 它只是在关闭GUI之前停止。直到图形用户界面关闭,程序才进入第4点。

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

    问题

    当一个组件试图在 doSuffor() (确切的代码行是组件运行时 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并在 应用程序.run() ?

    3 回复  |  直到 9 年前
        1
  •  11
  •   Ishmaeel    16 年前

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

    但是,您可以通过 应用程序上下文 (instad of a new form())to application.run方法和applicationContext可用于一次启动多个表单。只有当所有这些都关闭时,应用程序才会结束。请参见这里: http://msdn.microsoft.com/en-us/library/system.windows.forms.application.run.aspx

    此外,任何非模态显示的窗体都将继续与主窗体一起运行,这将使您拥有多个不相互阻塞的窗口。我相信这正是你想要达到的目标。

        2
  •  0
  •   Orion Edwards    16 年前

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

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

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

    你最好这样做:

    制作一张从未显示的假表单,这是您的“主应用程序” 启动 打电话申请。用这个假表格跑过去。 在另一个线程中执行您的工作,并在需要执行GUI操作时在主线程上触发事件。

        3
  •  0
  •   Sebastian Bender    16 年前

    我不确定这是否正确,但是我记得从控制台应用程序运行窗口窗体时,只需更新窗体并对其调用newForm.show(),如果您的组件使用它而不是application.run(),那么新窗体不应该阻塞。

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