c# - visual - winform guide




È possibile "far scattare" diversi thread GUI?(Non bloccare il sistema su Application.Run) (2)

Il mio obiettivo

Mi piacerebbe avere un thread di elaborazione principale (non GUI), ed essere in grado di far girare le GUI nei loro thread in background, se necessario, e avere il mio thread non GUI principale continua a funzionare. In altre parole, voglio che il mio thread principale non GUI sia il proprietario del thread della 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 gli assembly e crea istanze ed esegue classi implementando un'interfaccia IComponent comune con un singolo metodo DoStuff() .

Quali componenti vengono caricati viene configurato 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 cosa, ad esempio il controllo di una centrale nucleare, i componenti potrebbero svolgere compiti di utilità (nelle proprie discussioni), ad esempio pulire il database, inviare e-mail, stampare scherzi divertenti sulla stampante, cos'hai. Quello che vorrei, è che uno di questi componenti sia in grado di visualizzare una GUI, ad esempio con informazioni sullo stato per il suddetto componente di invio e-mail.

La durata del sistema completo è simile a questa

  1. L'applicazione inizia.
  2. Controllare il file di configurazione per i componenti da caricare. Caricali
  3. Per ogni componente, eseguire DoStuff() per inizializzarlo e farlo vivere la propria vita nei propri thread.
  4. Continua a fare il principale app di applicazione-cosa del mondo, per sempre.

Non sono ancora stato in grado di eseguire correttamente il punto 3 se il componente DoStuff() una GUI in DoStuff() . Si ferma semplicemente finché la GUI non viene chiusa. E non fino alla chiusura della GUI, il programma avanza fino al punto 4.

Sarebbe bello se a questi componenti fosse consentito avviare la propria GUI Windows Form.

Problema

Quando un componente tenta di DoStuff() una GUI in DoStuff() (la riga esatta del codice è quando il componente esegue Application.Run(theForm) ), il componente e quindi il nostro sistema "si blocca" sulla riga Application.Run() fino a quando la GUI è chiusa. Bene, la GUI appena accesa funziona bene, come previsto.

Esempio di componenti. Uno non ha niente a che fare con la GUI, mentre la seconda accende una finestra carina con coniglietti soffici rosa.

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

Ho provato questo senza fortuna. Anche quando provo a accendere la GUI nel proprio thread, l'esecuzione si arresta 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 eseguire lo spin off di una GUI e tornare dopo Application.Run() ?


Sono sicuro che questo è possibile se ci riesci abbastanza, ma suggerirei che non è una buona idea.

'Windows' (che vedi sullo schermo) sono altamente accoppiati ai processi. Cioè, ogni processo che visualizza una GUI dovrebbe avere un Loop dei messaggi, che elabora tutti i messaggi che sono coinvolti con la creazione e la gestione di finestre (cose come 'fa clic sul pulsante', 'chiudi l'app', 'ridisegna lo schermo ' e così via.

Per questo motivo, è più o meno scontato che se si dispone di un loop di messaggi, deve essere disponibile per tutta la durata del processo. Ad esempio, Windows potrebbe inviarti un messaggio di 'smettere', e devi avere un loop di messaggi disponibile per gestirlo, anche se non hai niente sullo schermo.

La tua migliore scommessa è farlo in questo modo:

Crea una forma falsa che non viene mai mostrata quale è la tua 'app principale' Start up Call Application.Run e passa in questa forma falsa. Esegui il tuo lavoro in un'altra discussione e attiva gli eventi nel thread principale quando hai bisogno di fare cose Gui.


Il metodo Application.Run visualizza uno (o più) moduli e avvia il ciclo di messaggi standard che viene eseguito fino alla chiusura di tutti i moduli. Non è possibile forzare un ritorno da quel metodo se non chiudendo tutti i moduli o forzando l'arresto di un'applicazione.

Tuttavia, è possibile passare un ApplicationContext (instad di una nuova Form ()) al metodo Application.Run e ApplicationContext può essere utilizzato per avviare più moduli contemporaneamente. La tua applicazione terminerà solo quando tutti quelli saranno chiusi. Vedi qui: http://msdn.microsoft.com/en-us/library/system.windows.forms.application.run.aspx

Inoltre, tutti i moduli visualizzati in modalità non modale continueranno a funzionare insieme al tuo modulo principale, che ti consentirà di avere più di una finestra che non si bloccano a vicenda. Credo che questo sia in realtà ciò che stai cercando di realizzare.







winforms