Possibilité de « créer » plusieurs threads d'interface graphique ?(Ne pas arrêter le système sur Application.Run)

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

  •  08-06-2019
  •  | 
  •  

Question

Mon but

J'aimerais avoir un thread de traitement principal (non GUI) et pouvoir créer des interfaces graphiques dans leurs propres threads d'arrière-plan si nécessaire, et 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 possible avec Windows Forms (?)

Arrière-plan

J'ai un système basé sur des composants dans lequel un contrôleur charge dynamiquement des assemblys, instancie et exécute des classes implémentant un commun IComponent interface avec une seule méthode DoStuff().

Les composants chargés sont configurés via un fichier de configuration XML et en ajoutant de nouveaux assemblys contenant différentes implémentations de IComponent.Les composants fournissent des fonctions utilitaires à l'application principale.Pendant que le programme principal fait son travail, par ex.contrôlant une centrale nucléaire, les composants peuvent effectuer des tâches utilitaires (dans leurs propres threads), par ex.nettoyer la base de données, envoyer des e-mails, imprimer des blagues amusantes sur l'imprimante, qu'avez-vous.Ce que j'aimerais, c'est que l'un de ces composants puisse afficher une interface graphique, par ex.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écutez DoStuff() pour l'initialiser et lui faire vivre sa propre vie dans ses propres threads.
  4. Continuez à faire le roi du travail des applications principales, pour toujours.

Je n'ai pas encore réussi à exécuter le point 3 si le composant lance une interface graphique dans DoStuff().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 passe au point 4.

Ce serait formidable si ces composants étaient autorisés à démarrer leur propre interface graphique Windows Forms.

Problème

Lorsqu'un composant tente de lancer une interface graphique dans DoStuff() (la ligne exacte de code correspond au moment où le composant s'exécute Application.Run(theForm)), le composant et donc notre système "se bloque" au Application.Run() ligne jusqu'à ce que l'interface graphique soit fermée.Eh bien, l'interface graphique qui vient d'être lancée fonctionne bien, comme prévu.

Exemple de composants.L'un n'a rien à voir avec l'interface graphique, tandis que le second ouvre de jolies fenêtres avec des lapins roses moelleux à l'intérieur.

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'essaie 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 désactiver une interface graphique et de revenir après Application.Run()?

Était-ce utile?

La solution

Application.Exécuter La méthode affiche un (ou plusieurs) formulaires et lance la boucle de messages 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 de l'application.

Vous pouvez cependant passer un Contexte d'application (au lieu d'un nouveau Form()) vers la méthode Application.Run et ApplicationContext peut être utilisé pour lancer plusieurs formulaires à la fois.Votre candidature ne prendra fin que lorsque toutes celles-ci seront fermées.Vois ici: http://msdn.microsoft.com/en-us/library/system.windows.forms.application.run.aspx

De plus, tous les formulaires que vous affichez de manière non modale continueront à s'exécuter parallèlement à votre formulaire principal, ce qui vous permettra d'avoir plusieurs fenêtres qui ne se bloquent pas les unes les autres.Je crois que c'est en fait ce que vous essayez d'accomplir.

Autres conseils

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.

Les « fenêtres » (que vous voyez à l'écran) sont fortement couplées aux processus.Autrement dit, chaque processus qui affiche une interface graphique est censé avoir une boucle de messages, 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). ' et ainsi de suite.

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

Le mieux est de procéder comme ceci :

Faire un faux formulaire qui n'est jamais montré qui est votre 'application principale' Démarrage Appelez Application.Exécutez et passez dans 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 avec Gui.

Je ne sais pas si c'est vrai, 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 devrait pas bloquer.

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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top