IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Windows Forms Discussion :

Ouvrir une Form aussi bien à partir d'une appli Console que d'une Windows Form


Sujet :

Windows Forms

  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 12
    Points : 3
    Points
    3
    Par défaut Ouvrir une Form aussi bien à partir d'une appli Console que d'une Windows Form
    Bonjour,
    j'ai besoin de créer une classe dans une Dll qui peut ouvrir une Windows Form en mode non-modal. Cette classe peut aussi bien être appelée d'une application en mode console (CUI) que d'une Windows Form (GUI). Pour les besoins de l'exemple, nous appellerons cette classe 'CalledForm'.
    Pour l'instant, voici les options autour desquelles j'ai prospecté:

    1/ la Form est ouverte avec Application.Run(CalledForm):
    a. mode Console: il faut que CalledForm soit fermée pour que ce qui est envoyé à la console soit lu.
    b. mode Form: plein de problèmes, soit des exceptions, soit CalledForm s'affiche à la place de l'autre Form, etc.

    2/ la Form est ouvert avec CalledForm.Show()
    a. mode Console: CalledForm s'ouvre, mais ne se dessine pas, et le curseur se met en sablier (la Form se bloque)
    b. mode Form: tout va bien. Ca semble bien la méthode idoine.

    après investigation sur le net, j'ai mis en place une solution tierce, qui consiste à 'threader' l'appel à Application.Run, dont voici les bases:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public partial class CalledForm: Form   
    {                  
            private Thread m_localThread = new Thread(Run);   
            private static void Run(Object frm)   
            {   
                Application.EnableVisualStyles();   
                Application.Run((Form)frm);   
            }   
            public void ThreadedShow()   
            {   
                if (!m_localThread.IsAlive)   
                    m_localThread.Start(this);   
            }   
     }
    3/ dans ce cas là, si la Form est ouverte avec CalledForm.ThreadedShow()
    a. mode Console. Tout va bien. C'est clairement la méthode recommandée.
    b. mode Form: ça marche, mais ce n'est pas optimale (CalledForm est clairement plus lente) et elle n'est pas fermée quand on quitte l'appli principale.

    Ma question est donc, comment puis-je, par programmation, savoir dans quel mode je suis, pour pouvoir appeler la bonne méthode (Show() ouThreadedShow()) ?

    A savoir:
    j'ai essayé Application.OpenForms, qui s'avère peu fiable, on peut se trouver dans des cas ou ça renvoie 0 alors que des formes sont en construction.
    j'ai égalemet essayé GetStdHandle et GetConsoleMode mais ce n'est pas fiable non plus.

  2. #2
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    547
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 547
    Points : 627
    Points
    627
    Par défaut
    Salut,

    dans le cas, d'une form threadé toute la logique de la form doit l'etre, et ce dans le meme thread (de sa creation à son "bouclage" ainsi que son dispose).

    Le fait que l'application initiale soit de type form ou console, ne change pas grand chose (d'ailleurs vu que l'appartment du thread initial d'une console n'est pas specifié, ca risque meme d'en créer à terme).

    Le mieux AMHA etant de proteger ton constructeur de form est de n'exposer la logique d'instanciation que par une methode statique, une implementation naive serait :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
        public partial class Form1 : Form
        {
            static Thread s_t;
            static Form1 s_form;
            private Form1()
            {
                InitializeComponent();
            }
     
            public static Form1 NewAndRun()
            {
                AutoResetEvent are = new AutoResetEvent(false);
                s_t = new Thread(
                    delegate()
                    {
                        s_form = new Form1();
                        Application.Idle +=
                            delegate
                            {
                                are.Set();
                            };
                        Application.Run(s_form);
     
                    });
                s_t.SetApartmentState(ApartmentState.STA);
                s_t.Start();
                are.WaitOne();
     
                return s_form;
            }
        }
    Dans ce cas, ta form a été créé et est géré par son propre thread (l'ARE est la pour empecher le renvoi d'une reference non construite). En recuperant la reference tu pourras l'utiliser coté utilisateur (attention cependant aux invocations necessaires).

    Bon courage.

  3. #3
    Candidat au Club
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 12
    Points : 3
    Points
    3
    Par défaut
    Salut SirJulio, et merci d'avoir pris du temps pour me répondre.

    Je ne suis pas sûr d'avoir bien compris, cependant.

    Mon problème, en résumé, est de pouvoir automatiser la decision à l'ouverture de la Form que propose ma Dll:

    • un simple 'Show()' standard dans le cas d'une appli à vocation GUI (qui va lancer un Application.Run d'une Form à un moment ou à un autre).

    • un 'ThreadedShow()' si c'est la seule fenêtre et que le reste est en console
      (grosso modo).


    Est-ce que ta réponse est d'améliorer le 'ThreadedShow' que je propose.
    Voire serait-il recommandé dans tous les cas de figure ?

    En ce qui me concerne, je serais bien enclin à rester sur un simple 'Show()' dans le cas d'une appli GUI.
    Dans ce cas, comment verrais-tu le test qui me permets de savoir dans quel mode je suis?

    Je vais tester la solution que tu proposes, mais elle me paraît alambiquée (ce n'est pas de ton fait, évidemment).
    Déjà que l'implentation du 'ThreadedShow()' me paraîssait lourde...

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    547
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 547
    Points : 627
    Points
    627
    Par défaut
    Salut eTill,

    le probleme va venir de comment detecter efficacement la presence d'une loop ou non. Tu peux utiliser bool Application.MessageLoop() pour verifier qu'une boucle est presente (auquel cas un simple Show() suffira en effet), mais cela est restreint au thread appelant.

    De fait si ta methode est appelé en async (par un worker thread par exemple), tu risques de ne pas pouvoir detecter une boucle deja presente. De fait, il faudra aussi voir que ta form sera dependante d'une boucle coté utilisateur (Si il ferme toutes ses fenetres, la tienne retiendra le contexte, il faudra d'une maniere ou d'une autre synchronisé la fermeture de ta fenetre avec le reste de l'UI utilisateur).

    De toutes facons, je suis tout à fait d'accord que les repartitions de presentations sur plusieurs threads n'est pas une bonne idée, mais la à part forcer (par documentation j'entends) l'utilisateur à appeller la methode sur un thread bouclé, je ne vois pas trop comment faire ca proprement.

  5. #5
    Candidat au Club
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 12
    Points : 3
    Points
    3
    Par défaut
    OK,
    l'attribut 'Application.MessageLoop' n'est pas pour me déplaire, avec les limitations que tu mets en valeur.
    Dans le cas où il retournerait 'false', penses-tu que l'implementation d'un simple 'ThreadedShow' pourrait être suffisante, ou bien vaut-il mieux passer pas le mécanisme que tu propose ?

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    547
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 547
    Points : 627
    Points
    627
    Par défaut
    Et bien, c'est justement le probleme, je ne vois pas trop comment faire ca simplement. =)

    Le threadedShow me parait la solution "la moins pire", à ceci pret qu'il faut, AMHA, garder le controle sur la construction de la form, et ne pas laisser la form se ballader entre deux threads.

    Bref, ta solution devrait fonctionner (vu que les creations d'handle avec .Net sont pour la plupart retardé, tu ne devrais pas avoir de problemes). Il restera juste le probleme des appels depuis un thread secondaire sur une appli GUI, mais la tu ne peux rien faire (du moins pas à ma connaissance).

  7. #7
    Candidat au Club
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 12
    Points : 3
    Points
    3
    Par défaut
    OK.
    Après avoir longuement hésité. Je crois que je vais utiliser Application.MessageLoop comme test sur le contexte de lancement.
    Par exemple, ça réagit bien dans le cas où la Form est lancée à partir d'un "BackGroundWorker' (rapidement testé, il est vrai).

    Je comprends aussi mieux ce que tu propose pour 'totalement threader' l'utilisation de la Form.
    C'est d'ailleurs probablement la solution finale que je vais implanter (pour le mode 'Threaded'). Il y a juste le fait que le Thread soit du coup en static qui me gêne un peu.

    Merci, en tous cas de tes conseils éclairés.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. HttpWebRequest fonctionne sur une appli console, pas sur une appli Web
    Par hollywood dans le forum Général Dotnet
    Réponses: 4
    Dernier message: 23/04/2009, 14h34
  2. [C++ .NET] Disposer d'une console de déboguage en Windows Form
    Par pierre.chatelier dans le forum C++/CLI
    Réponses: 4
    Dernier message: 04/09/2007, 14h31
  3. [C++ .NET] Disposer d'une console de déboguage en Windows Form
    Par pierre.chatelier dans le forum Général Dotnet
    Réponses: 0
    Dernier message: 04/09/2007, 13h18
  4. Ouvrir une même Form x fois à partir de y Forms
    Par Hobbi1 dans le forum VB 6 et antérieur
    Réponses: 2
    Dernier message: 09/09/2006, 11h50
  5. Ouvrir une page web a partir d'un programme
    Par acieroid dans le forum C++
    Réponses: 2
    Dernier message: 15/05/2006, 17h48

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo