c# - Possible de "dériver" plusieurs threads GUI? (Ne pas arrêter le système à Application.Run)

Translate

Mon but

Je voudrais avoir un thread de traitement principal (non GUI), et être capable de créer des interfaces graphiques dans leurs propres threads d'arrière-plan si nécessaire, et faire en sorte que mon thread principal non GUI continue de fonctionner. En d'autres termes, je veux que mon thread principal non GUI soit le propriétaire du thread GUI et non l'inverse. Je ne suis pas sûr que cela soit même possible avec Windows Forms (?)

Contexte

J'ai un système basé sur des composants dans lequel un contrôleur charge dynamiquement des assemblages et instancie et exécute des classes mettant en œuvre unIComponentinterface avec une seule méthodeDoStuff().

Les composants qui sont chargés sont configurés via un fichier de configuration xml et en ajoutant de nouveaux assemblys contenant différentes implémentations deIComponent. Les composants fournissent des fonctions utilitaires à l'application principale. Pendant que le programme principal fait son travail, par exemple contrôler une centrale nucléaire, les composants peuvent effectuer des tâches utilitaires (dans leurs propres threads), par exemple nettoyer la base de données, envoyer des e-mails, imprimer des blagues amusantes sur l'imprimante, etc. Ce que je voudrais, c'est que l'un de ces composants puisse afficher une interface graphique, par exemple avec des informations d'état pour ledit composant d'envoi d'e-mails.

La durée de vie du système complet ressemble à ceci

  1. L'application démarre.
  2. Vérifiez le fichier de configuration pour les composants à charger. Chargez-les.
  3. Pour chaque composant, exécutezDoStuff()pour l'initialiser et lui faire vivre sa propre vie dans leurs propres threads.
  4. Continuez à faire le roi du travail, pour toujours.

Je n'ai pas encore été en mesure d'exécuter avec succès le point 3 si le composant déclenche une interface graphique dansDoStuff(). Il s'arrête simplement jusqu'à ce que l'interface graphique soit fermée. Et ce n'est que lorsque l'interface graphique est fermée que le programme progresse jusqu'au point 4.

Ce serait formidable si ces composants étaient autorisés à démarrer leurs propres interfaces graphiques Windows Forms.

Problème

Lorsqu'un composant tente de déclencher une interface graphiqueDoStuff()(la ligne de code exacte correspond au moment où le composant s'exécuteApplication.Run(theForm)), le composant et donc notre système "se bloque" auApplication.Run()ligne jusqu'à ce que l'interface graphique soit fermée. Eh bien, l'interface graphique qui vient de démarrer fonctionne correctement, comme prévu.

Exemple de composants. L'un n'a rien à voir avec l'interface graphique, tandis que le second déclenche une jolie fenêtre avec des lapins roses moelleux.

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

J'ai essayé cela sans succès. Même lorsque j'essaye de lancer l'interface graphique dans son propre thread, l'exécution s'arrête jusqu'à ce que l'interface graphique soit fermée.

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

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

Est-il possible de créer une interface graphique et de revenir aprèsApplication.Run()?

This question and all comments follow the "Attribution Required."

Toutes les réponses

Translate

Application.ExécuterLa méthode affiche un (ou plusieurs) formulaires et lance la boucle de message standard qui s'exécute jusqu'à ce que tous les formulaires soient fermés. Vous ne pouvez pas forcer un retour à partir de cette méthode sauf en fermant tous vos formulaires ou en forçant l'arrêt d'une application.

Vous pouvez cependant passer unApplicationContext(instad d'un nouveau Form ()) à la méthode Application.Run et ApplicationContext peuvent être utilisés pour lancer plusieurs formulaires à la fois. Votre candidature ne se terminera que lorsque tous seront fermés. Vois ici:http://msdn.microsoft.com/en-us/library/system.windows.forms.application.run.aspx

En outre, tous les formulaires que vous affichez de manière non modale continueront à fonctionner parallèlement à votre formulaire principal, ce qui vous permettra d'avoir plusieurs fenêtres qui ne se bloquent pas. Je crois que c'est en fait ce que vous essayez d'accomplir.

La source
Translate

Je suis sûr que cela est possible si vous le piratez assez fort, mais je dirais que ce n'est pas une bonne idée.

«Windows» (que vous voyez à l'écran) sont fortement couplés aux processus. Autrement dit, chaque processus qui affiche une interface graphique doit avoir une boucle de message, qui traite tous les messages impliqués dans la création et la gestion des fenêtres (des choses comme `` cliqué sur le bouton '', `` fermé l'application '', `` redessiner l'écran ' etc.

Pour cette raison, il est plus ou moins supposé que si vous avez une boucle de message, elle doit être disponible pour la durée de vie de votre processus. Par exemple, Windows peut vous envoyer un message «Quitter», et vous devez avoir une boucle de message disponible pour gérer cela, même si vous n'avez rien à l'écran.

Votre meilleur pari est de le faire comme ceci:

Créez un faux formulaire qui n'est jamais affiché, qui est votre `` application principale ''. Démarrez l'application d'appel. Exécutez et transmettez ce faux formulaire. Faites votre travail dans un autre thread et déclenchez des événements sur le thread principal lorsque vous avez besoin de faire des choses Gui.

La source
Translate

Je ne suis pas sûr que ce soit correct, mais je me souviens avoir exécuté des formulaires de fenêtre à partir d'une application console en renouvelant simplement le formulaire et en appelant newForm.Show () dessus, si vos composants l'utilisent au lieu de Application.Run (), alors le nouveau le formulaire ne doit pas bloquer.

Bien entendu, le composant sera chargé de maintenir une référence aux formulaires qu'il crée

La source