È possibile "separare" diversi thread della GUI?(Non arrestare il sistema in Application.Run)

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

  •  08-06-2019
  •  | 
  •  

Domanda

Il mio obiettivo

Mi piacerebbe avere un thread di elaborazione principale (non GUI) ed essere in grado di creare GUI nei propri thread in background secondo necessità e far sì che il mio thread principale non GUI continui a funzionare.In altre parole, voglio che il mio thread principale non GUI sia il proprietario del thread GUI e non viceversa.Non sono sicuro che ciò sia possibile anche con Windows Forms(?)

Sfondo

Ho un sistema basato su componenti in cui un controller carica dinamicamente assembly, istanzia ed esegue classi che implementano un file common IComponent interfacciarsi con un unico metodo DoStuff().

I componenti che vengono caricati vengono configurati tramite un file di configurazione xml e aggiungendo nuovi assembly contenenti diverse implementazioni di IComponent.I componenti forniscono funzioni di utilità all'applicazione principale.Mentre il programma principale sta facendo la sua cosa, ad es.controllando una centrale nucleare, i componenti potrebbero svolgere compiti di utilità (nei propri thread), ad es.pulire il database, inviare e-mail, stampare barzellette divertenti sulla stampante, cos'hai.Quello che mi piacerebbe è che uno di questi componenti sia in grado di visualizzare una GUI, ad es.con informazioni sullo stato del suddetto componente di invio di posta elettronica.

La durata del sistema completo è simile a questa

  1. L'applicazione viene avviata.
  2. Controllare il file di configurazione per i componenti da caricare.Caricateli.
  3. Per ogni componente, esegui DoStuff() per inizializzarlo e fargli vivere vita propria nei propri thread.
  4. Continua a fare l'applicazione principale del lavoro, per sempre.

Non sono ancora riuscito a eseguire con successo il punto 3 se il componente avvia una GUI DoStuff().Si ferma semplicemente finché la GUI non viene chiusa.E solo quando la GUI viene chiusa il programma avanza al punto 4.

Sarebbe fantastico se a questi componenti fosse consentito avviare le proprie GUI Windows Forms.

Problema

Quando un componente tenta di avviare una GUI in DoStuff() (la riga di codice esatta è quando viene eseguito il componente Application.Run(theForm)), il componente e quindi il nostro sistema "si blocca" su Application.Run() linea finché la GUI non viene chiusa.Bene, la GUI appena avviata funziona bene, come previsto.

Esempio di componenti.Uno non ha nulla a che fare con la GUI, mentre il secondo attiva delle graziose finestre con soffici coniglietti rosa al loro interno.

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

L'ho provato senza fortuna.Anche quando provo ad avviare la GUI nel proprio thread, l'esecuzione si interrompe finché la GUI non viene chiusa.

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

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

È possibile separare una GUI e tornare dopo Application.Run()?

È stato utile?

Soluzione

Applicazione.Esegui Il metodo visualizza uno (o più) moduli e avvia il ciclo di messaggi standard che viene eseguito finché tutti i moduli non vengono chiusi.Non è possibile forzare una restituzione da quel metodo se non chiudendo tutti i moduli o forzando la chiusura dell'applicazione.

Puoi, tuttavia, superare un Contesto dell'applicazione (invece di un nuovo Form()) al metodo Application.Run e ApplicationContext può essere utilizzato per avviare più moduli contemporaneamente.La tua applicazione terminerà solo quando tutti questi saranno chiusi.Vedere qui: http://msdn.microsoft.com/en-us/library/system.windows.forms.application.run.aspx

Inoltre, tutti i moduli che mostri in modo non modale continueranno a essere eseguiti insieme al modulo principale, il che ti consentirà di avere più di una finestra che non si bloccano a vicenda.Credo che questo sia effettivamente ciò che stai cercando di realizzare.

Altri suggerimenti

Sono sicuro che questo sia possibile se lo hackeri abbastanza duramente, ma suggerirei che non sia una buona idea.

Le "finestre" (che vedi sullo schermo) sono altamente accoppiate ai processi.Cioè, ogni processo che visualizza una GUI dovrebbe avere un Message Loop, che elabora tutti i messaggi coinvolti nella creazione e gestione delle finestre (cose come "ha fatto clic sul pulsante", "ha chiuso l'app", "ridisegna lo schermo" ' e così via.

Per questo motivo, si presume più o meno che, se si dispone di un ciclo di messaggi, esso debba essere disponibile per tutta la durata del processo.Ad esempio, Windows potrebbe inviarti un messaggio di "esci" e devi avere a disposizione un ciclo di messaggi per gestirlo, anche se non hai nulla sullo schermo.

La soluzione migliore è farlo in questo modo:

Crea una forma falsa che non viene mai mostrata che è l'applicazione di chiamata di avvio "App principale" e passa in questa forma falsa.Fai il tuo lavoro in un altro thread e attiva gli eventi nel thread principale quando hai bisogno di fare cose su Gui.

Non sono sicuro che sia corretto, tuttavia ricordo di aver eseguito i moduli finestra da un'applicazione console semplicemente rinnovando il modulo e chiamando newForm.Show() su di esso, se i tuoi componenti lo usano invece di Application.Run() quindi il nuovo il modulo non dovrebbe bloccarsi.

Naturalmente il componente sarà responsabile di mantenere un riferimento ai form che crea

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top