Possible to “spin off” several GUI threads? (Not halting the system at Application.Run)

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

  •  08-06-2019
  •  | 
  •  

Question

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(?)

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().

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.

The lifetime of the complete system looks like this

  1. Application starts.
  2. Check configuration file for components to load. Load them.
  3. For each component, run DoStuff() to initialize it and make it live its own life in their own threads.
  4. Continue to do main application-thingy king of work, forever.

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.

It would be great if these components were allowed to start up their own Windows Forms GUIs.

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.

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.

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.

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()?

Was it helpful?

Solution

Application.Run method 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.

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

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.

OTHER TIPS

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.

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.

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.

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.

Of course the component will be responsible for maintaining a reference to the forms it creates

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top