¿Es posible “escindir” varios subprocesos de GUI?(Sin detener el sistema en Application.Run)

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

  •  08-06-2019
  •  | 
  •  

Pregunta

Mi meta

Me gustaría tener un subproceso de procesamiento principal (sin GUI) y poder generar GUI en sus propios subprocesos en segundo plano según sea necesario, y que mi subproceso principal sin GUI siga funcionando.Dicho de otra manera, quiero que mi hilo principal que no es GUI sea el propietario del hilo GUI y no al revés.No estoy seguro de que esto sea posible con Windows Forms (?)

Fondo

Tengo un sistema basado en componentes en el que un controlador carga dinámicamente ensamblajes, crea instancias y ejecuta clases que implementan un sistema común. IComponent interfaz con un solo método DoStuff().

Los componentes que se cargan se configuran mediante un archivo de configuración xml y agregando nuevos ensamblados que contienen diferentes implementaciones de IComponent.Los componentes proporcionan funciones de utilidad a la aplicación principal.Mientras el programa principal hace su trabajo, p.e.Al controlar una planta nuclear, los componentes podrían estar realizando tareas de servicios públicos (en sus propios subprocesos), p.limpiar la base de datos, enviar correos electrónicos, imprimir chistes graciosos en la impresora, lo que sea.Lo que me gustaría es que uno de estos componentes pueda mostrar una GUI, por ejemplo.con información de estado para dicho componente de envío de correo electrónico.

La vida útil del sistema completo se ve así

  1. Se inicia la aplicación.
  2. Verifique el archivo de configuración para ver los componentes que se cargarán.Cárgalos.
  3. Para cada componente, ejecute DoStuff() para inicializarlo y hacerle vivir su propia vida en sus propios hilos.
  4. Continúe haciendo el trabajo principal, el rey de las aplicaciones, para siempre.

Todavía no he podido realizar con éxito el punto 3 si el componente activa una GUI en DoStuff().Simplemente se detiene hasta que se cierra la GUI.Y no es hasta que se cierra la GUI que el programa avanza al punto 4.

Sería fantástico si a estos componentes se les permitiera iniciar sus propias GUI de Windows Forms.

Problema

Cuando un componente intenta iniciar una GUI en DoStuff() (la línea exacta de código es cuando se ejecuta el componente Application.Run(theForm)), el componente y por lo tanto nuestro sistema "se cuelga" en el Application.Run() línea hasta que se cierre la GUI.Bueno, la GUI recién iniciada funciona bien, como se esperaba.

Ejemplo de componentes.Uno no tiene nada que ver con la GUI, mientras que el segundo abre unas lindas ventanas con conejitos rosados ​​y esponjosos.

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.
    }
}

He intentado esto sin suerte.Incluso cuando intento iniciar la GUI en su propio hilo, la ejecución se detiene hasta que la GUI se cierra.

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

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

¿Es posible separar una GUI y regresar después? Application.Run()?

¿Fue útil?

Solución

Aplicación.Ejecutar El método muestra uno (o más) formularios e inicia el bucle de mensajes estándar que se ejecuta hasta que se cierran todos los formularios.No puede forzar una devolución desde ese método, excepto cerrando todos sus formularios o forzando el cierre de la aplicación.

Sin embargo, puedes pasar un Contexto de aplicación (en lugar de un nuevo Form()) al método Application.Run y ​​ApplicationContext se pueden usar para iniciar varios formularios a la vez.Su aplicación solo finalizará cuando todas estén cerradas.Mira aquí: http://msdn.microsoft.com/en-us/library/system.windows.forms.application.run.aspx

Además, cualquier formulario que muestre de forma no modal continuará ejecutándose junto con su formulario principal, lo que le permitirá tener más de una ventana que no se bloquee entre sí.Creo que esto es realmente lo que estás tratando de lograr.

Otros consejos

Estoy seguro de que esto es posible si lo pirateas lo suficiente, pero sugeriría que no es una buena idea.

Los 'Windows' (que ves en la pantalla) están altamente acoplados a los procesos.Es decir, se espera que cada proceso que muestra cualquier GUI tenga un bucle de mensajes, que procesa todos los mensajes relacionados con la creación y administración de ventanas (cosas como "hice clic en el botón", "cerré la aplicación", "volví a dibujar la pantalla" ' etcétera.

Debido a esto, se supone más o menos que si tiene algún bucle de mensajes, debe estar disponible durante toda la vida de su proceso.Por ejemplo, Windows puede enviarle un mensaje de "salir" y necesita tener un bucle de mensajes disponible para manejarlo, incluso si no tiene nada en la pantalla.

Lo mejor que puedes hacer es hacerlo así:

Haga un formulario falso que nunca se muestre cuál es su aplicación de llamadas de inicio 'la aplicación principal'.Haga su trabajo en otro hilo y active eventos en el hilo principal cuando necesite hacer cosas de Gui.

No estoy seguro de si esto es correcto, sin embargo, recuerdo haber ejecutado formularios de ventana desde una aplicación de consola simplemente actualizando el formulario y llamando a newForm.Show() en él, si sus componentes usan eso en lugar de Application.Run() entonces el nuevo El formulario no debería bloquearse.

Por supuesto el componente será responsable de mantener una referencia a los formularios que crea.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top