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 Presentation Foundation Discussion :

Portage Console vers WPF et programme en boucle C# [Débutant]


Sujet :

Windows Presentation Foundation

  1. #1
    Membre du Club
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Octobre 2015
    Messages
    98
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Santé

    Informations forums :
    Inscription : Octobre 2015
    Messages : 98
    Points : 59
    Points
    59
    Par défaut Portage Console vers WPF et programme en boucle C#
    Bonsoir à tous,

    Voila j'ai un soucis surement idiot mais j'ai un problème avec l'instanciation en générale.
    Je suis en cours de portage d'une application console qui marche très bien vers du WPF tous nouveau pour moi.
    j'ai lu quelques topic mais c'est sur la logique de fonctionnement que je bloc.

    Ma question est super moisi : De qu'elle façon je peut boucler une application pour qu'elle recommence à l'infini ?
    En console c'est très simple, une boucle while et ça roule.

    En WPF je comprend pas le fonctionnement... J'ai tester les actions type clic qui fonctionne un peu comme du web pas de soucis et je crois comprendre que Window_Loaded() est un peu le Main() du mode console mais pour le reste...

    je voudrais savoir comment repartir au debut du Window_Loaded a la fin du déroulement de l'application. Une boucle while volontairement infini dans le Window_Loaded charge une fenêtre blanche et il ne se passe rien. J'ai pas réellement besoin des interactions type "clic" en vérité. Je veut juste boucler un process automatique assez complexe et pouvoir afficher proprement tout un tas de valeur dans des textblock qui évolue a chaque cycle, sorte de "rafraîchissement".

    Pour l'instant je tente par exemple un truc dans ce style:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    int testeur = 150;
    int ncycle = 0;
    private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                while (testeur > 0)
                {
                    debut();
                    Fin();
                    ncycle++;
                    label2.Content = Convert.ToString(ncycle);
                }
            }
    page blanche, rien ne s'affiche et le programme mouline. Je voudrais qu'a la fin de la boucle while on redémarre depuis la méthode debut() et que les valeurs dans les méthode debut() et fin() "se rafraîchisse".
    Voila si vous aviez un exemple ou une explications des mécanisme à l'oeuvre sa serais sympas.


    Merci de votre aide et bonne soirée

  2. #2
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    l'interface (winforms ou wpf) est rafraichit via le thread principal
    donc déjà si tu exécutes du code non stop sur ce thread ton appli va freezer

    il te faut donc un autre thread, où tu pourras faire un while true
    par contre une boucle sans pause ca peut consommer beaucoup de ressources processeur, donc idéalement il faut trouver un délai (1 ms c'est déjà mieux que rien) pour exécuter le code (thread.sleep(x ms) dans le while)

    si ton code s'exécute vite et toujours vite (moins de 500ms) alors tu peux te passer du thread et utiliser un timer
    c'est un objet sur lequel tu choisis un interval et qui lève un évènement tous les tant de temps, dans lequel tu peux exécuter du code et modifier l'interface

    autre chose, depuis un autre thread il est impossible de modifier l'interface utilisateur
    là 2 solutions, soit utiliser des délégués pour "revenir temporairement" sur le thread principal, soit utiliser un timer qui va lire les variables que ton thread aura écrit
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  3. #3
    Membre régulier
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2013
    Messages
    51
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2013
    Messages : 51
    Points : 72
    Points
    72
    Par défaut
    Citation Envoyé par Pol63 Voir le message
    l'interface (winforms ou wpf) est rafraichit via le thread principal
    donc déjà si tu exécutes du code non stop sur ce thread ton appli va freezer

    il te faut donc un autre thread, où tu pourras faire un while true
    par contre une boucle sans pause ca peut consommer beaucoup de ressources processeur, donc idéalement il faut trouver un délai (1 ms c'est déjà mieux que rien) pour exécuter le code (thread.sleep(x ms) dans le while)

    si ton code s'exécute vite et toujours vite (moins de 500ms) alors tu peux te passer du thread et utiliser un timer
    c'est un objet sur lequel tu choisis un interval et qui lève un évènement tous les tant de temps, dans lequel tu peux exécuter du code et modifier l'interface

    autre chose, depuis un autre thread il est impossible de modifier l'interface utilisateur
    là 2 solutions, soit utiliser des délégués pour "revenir temporairement" sur le thread principal, soit utiliser un timer qui va lire les variables que ton thread aura écrit
    Idem, utilisation d'un thread avec Application.Current.Dispatcher.Invoke ou BeginInvoke si tu veux modifier l'IHM.

  4. #4
    Membre du Club
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Octobre 2015
    Messages
    98
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Santé

    Informations forums :
    Inscription : Octobre 2015
    Messages : 98
    Points : 59
    Points
    59
    Par défaut
    bonjour ,
    merci pour votre aide.
    je vais creuser les notions de timer et de thread plus en détail.

    J'avais du mal a dissocier l'affichage en soi même et résultat d’opération qu'on ne distingue pas vraiment en console.
    Je vais creuser la chose et revenir faire part de mes découvertes

    encore merci

  5. #5
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    Bonjour
    Tu peux utiliser DoEvents pour traiter les events dans la pompe des messages Windows ,mais attention il ne faut pas manipuler de controls dans ta boucle après l'appel à DoEvents ,ne le faire qu'après sortie de boucle :
    exemple code :
    1/code xaml du form:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    <Window x:Class="WpfDoEvents.Window2"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Window2" Height="300" Width="300"
            Loaded="Window_Loaded">
        <StackPanel>
     
     
            <Label x:Name="label1"/>
        </StackPanel>
    </Window>
    2/code behind.cs du form:
    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
     
    namespace WpfDoEvents
    {
        /// <summary>
        /// Logique d'interaction pour Window2.xaml
        /// </summary>
        public partial class Window2 : Window
        {
            int testeur = 150;
            int ncycle = 0;
            bool b = false;
            public Window2()
            {
                InitializeComponent();
            }
            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                b = true;
                LoadNumbers(b );
            }
     
            private void LoadNumbers(bool callDoEvents)
            {
     
              //ATTENTION :ne pas acceder à des controls apres l'appel à DoEvents 
              // acceder seulement apres sortie de boucle while pour fermer la fenetre Window2
               while (testeur > 0)
                {
                    Debut();
                    Fin();
                    ncycle++;
     
                   label1.Content = Convert.ToString(ncycle);
                   if (callDoEvents)
                       DoEvents();
     
               }
     
            }
            private void Debut()
            { }
            private void Fin()
            { }
     
     
     
            // Process all messages in the current dispatcher queue
            public static void DoEvents()
            {
                // Add an empty delegate to the
                // current thread's Dispatcher, and
                // invoke it synchronously but using a
                // a Background priority.
                // It won't return until all higher-priority
                // events in the queue are processed.
                Dispatcher.CurrentDispatcher.Invoke(
                DispatcherPriority.Background,
                new EmptyDelegate(
                delegate { }));
            }
            private delegate void EmptyDelegate();
     
     
        }
    }
    bon code....

  6. #6
    Membre du Club
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Octobre 2015
    Messages
    98
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Santé

    Informations forums :
    Inscription : Octobre 2015
    Messages : 98
    Points : 59
    Points
    59
    Par défaut
    bonsoir merci pour ces explications. Je comprend mieux la philosophie du machin.
    J'ai toujours évité soigneusement les delegate et compagnie va falloir que je m'y colle du coup.

    visiblement plusieurs option s'offre à moi je vais donc voir la quelle correspond le mieux a mon besoin.

    Encore merci pour votre aide et je reviens quant j'ai une solution correct à présenter.

    ++

  7. #7
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    DoEvents est un bricolage plutôt qu'une solution
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  8. #8
    Membre régulier
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2013
    Messages
    51
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2013
    Messages : 51
    Points : 72
    Points
    72
    Par défaut
    A ma connaissance DoEvents n'existe pas en WPF, il existe uniquement en WinForm. On peut s'en bricoler un cependant (recherche google) mais la solution du thread est plus adaptée.

  9. #9
    Expert confirmé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2009
    Messages
    2 025
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Novembre 2009
    Messages : 2 025
    Points : 5 462
    Points
    5 462
    Par défaut
    Pas besoin d'en bricoler un, MABROUKI en fourni un .
    Mais c'est vrai que c'est franchement pas propre, et meme s'il est vrai que des fois ca simplifie la vie, ici tu ne devrais pas partir sur cette solution.

    Les applications winform et wpf sont basés sur un systeme d'évenement.
    En gros la boucle que toi tu fais dans une application console, les frameworks graphiques le font pour toi en appelant à chaque iteration les logiques de dessins et de gestions d'évenements.
    Si toi tu fais une boucle tu ne donnes pas la possibilité au framework de continuer dans sa propre boucle (et donc pplus d'appel aux rafraichissements, ni gestion des evenements tels que les cliques) d'ou la fenetre blanche et/ou freeze.

    Bref tout ca pour dire qu'il y a une infinité de possibilité pour contourner la situation mais mieux vaut partir sur du propre .
    Passer par un Thread comme Pol63 est une bonne facon, mais peut etre un peu lourd puisqu'il faut gérer le retour dans le Thread UI via le dispatcher, et comme il le mentionne tu peux utiliser un timer.
    Je complete cette piste par l'utilisation du DispatcherTimer.
    Il s'agit d'un timer que tu configures pour appeler une fonction toute les x secondes, avec en plus la gestion intégrée du dispatcher (quand ta fonction est appelée elle se trouve dans le contexte de l'UI).
    Tu peux rajouter un booleen pour t'assurer que ta fonction n'est pas appelées plusieurs fois en meme temps, dans le cas ou par exemple tu as mis un interval tres court.

    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
    DispatcherTimer _dispatcher;
            bool _isRunning;
     
            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                _dispatcher = new DispatcherTimer();
                _dispatcher.Interval = TimeSpan.FromSeconds(1); // Le delai qui te semble le plus opportun
                _dispatcher.Tick += _dispatcher_Tick;
                _dispatcher.Start();
     
            }
     
            private void _dispatcher_Tick(object sender, EventArgs e)
            {
                if (_isRunning)
                    return;
                _isRunning = true;
     
                debut();
                Fin();
                ncycle++;
                label2.Content = Convert.ToString(ncycle);
     
                if (testeur <= 0)
                    _dispatcher.Stop();
                _isRunning = false;
     
            }
    Edit: il n'en reste pas moins que l'on sait pas le temps d'execution de ton debut() et fin() !. S'ils sont long ca va toujours freezer l'interface le temps de leurs execution .
    Dans ce cas là tu peux toujours regarder le Thread, le BackgroundWorker, ou bien dès à présent apprendre async/await .

  10. #10
    Membre du Club
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Octobre 2015
    Messages
    98
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Santé

    Informations forums :
    Inscription : Octobre 2015
    Messages : 98
    Points : 59
    Points
    59
    Par défaut
    Bonsoir,
    Bon histoire de montrer que j'ai pas rien foutu, endormi au fond de mon bureau : ) je dévoile un code qui marche et qui effectivement m’amène à vos conclusions.

    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
     
    bool test = true;
    int ncycle = 0;
    private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                // Déclaration du thread
                Thread mytread;
     
                mytread = new Thread(Debut);
     
                // Lancement du thread
                mytread.Start();           
            }
     
    public void Debut()
            {
                // Tant que le cycle est inf a 20, on travaille
                while (ncycle <20)
                //while (Thread.CurrentThread.IsAlive)
                {
                    if (test == true)
                    {
                        // Wait for 3sec
                        Thread.Sleep(300);
     
                        string Presentation = "VALEUR A";
     
                        toto.Dispatcher.Invoke(
                        System.Windows.Threading.DispatcherPriority.Normal,
                        new Action(
                        delegate ()
                        {
                            toto.Text = Presentation;
                        }
                        ));
                        test = false;
                        ncycle++;
                    }
                    else
                    {
                        Thread.Sleep(300);
     
                        string Presentation = "B Valeur";
     
                        toto.Dispatcher.Invoke(
                        System.Windows.Threading.DispatcherPriority.Normal,
                        new Action(
                        delegate ()
                        {
                            toto.Text = Presentation;
                        }
                        ));
                        test = true;
                    }
                }
            }
    j'ai fait une alternance de choix juste pour avoir le plaisir, pour la 1ère fois, de voir quelque chose s'animé sur ma fenêtre *frissons*

    Pour les constats:
    1) je n'utiliserai pas la puissance des threads. c'est à présent un fait ;( . Clairement j'arrive sur le WPF pour le coté graphique car a part le threads principale je n'utiliserai qu'un autre threads, ma boucle (enfin pour le moment). C'est une programmation purement séquentielle façon cascade d’événement en chaîne dont la conclusion réamorce pour le tour suivant le processus. J'ai même envie de dire surtout pas de thread parce que 50 variables liés par des équations différentielles si on saute une ligne j'imagine même pas les crash faussement aléatoire (et alors comprendre la ou ça a foiré....). J'ai un réseau de neurone en fin de process qui fonctionne en plus (et ça tien un peu du miracle) je le laisse se gérer tous seul, c'est pas moi qui irai le synchroniser...

    2) effectivement je peut pas caler au-temps de dispatch que de variable à observer. Trop complexe, la j'en ai une seul sur mon exemple c'est déjà lourd à coder je trouve (par rapport à un bête Console.WriteLine()).

    3) le timer semble bien correspondre a ce que je cherche en ce sens qu'il fait tous les X seconde une sorte de point d'étape en affichant les variables existante ce qui me va très bien. Comme je n’interviens pas sur le processus et que je suis juste un observateur j'aurais juste une 50aine de textbloc sur ma fenêtre.
    Ce qui m’inquiète un peu c'est cette notion d'intervalle de temps du timer. Mon processus n'aura pas un temps de traitement uniforme à chaque boucle, il va même avoir tendance à ralentir (nombre d'exemple à tester qui s'accumule dans le fichier textes pour le réseau de neurone par exemple). Est-il possible dans un timer plutôt que d'avoir un intervalle de temps d'avoir une sorti de valeur à chaque fin de boucle par exemple?

    Je vais aller explorer le timer ça m'a l'air sympathique

    encore merci pour votre aide.

    je reviens avec du code dès que ça envoi du bois.

  11. #11
    Membre du Club
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Octobre 2015
    Messages
    98
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Santé

    Informations forums :
    Inscription : Octobre 2015
    Messages : 98
    Points : 59
    Points
    59
    Par défaut
    Citation Envoyé par micka132 Voir le message
    Edit: il n'en reste pas moins que l'on sait pas le temps d'execution de ton debut() et fin() !. S'ils sont long ca va toujours freezer l'interface le temps de leurs execution .
    Dans ce cas là tu peux toujours regarder le Thread, le BackgroundWorker, ou bien dès à présent apprendre async/await .

    Oui tu as raison mais c'est ma faute. J'ai voulu sortir 2 méthodes pour voir comment elle pouvait interagir a l’extérieur de ma méthode principale (ou exploser mon code en plusieurs méthodes) alors qu'en faite je peut mettre la totalité de la boucle (du programme ) dans un seul threads et le laissé dérouler sans l'interrompre (a condition de pouvoir de temps en temps lui extirper la valeurs des variables qu'il est en train de manipuler pour pouvoir les observer).

    Pour le reste ce que je peut dire sur la notion de temps:
    -Temps d’exécution de la boucle = inconnue mais variable, avec tendance au ralentissement au fur et a mesure.
    -Le programme utilise son propre référentiel temporel. Un tour de boucle = 1 unité de temps (on peut prendre comme comparaison un battement cardiaque. Il peut se passer des tas de phénomène entre 2 battements mais pour le programme c'est +1 battement, que le processus dur réellement 1sec ou 1 heures du coté observateur.
    -Selon ce fonctionnement le timer me sert uniquement a ralentir le processus. Je cale un délai de 1 sec d'attente avant de repartir dans la boucle ce qui me laisse le temps d'observer ce qu'il se passe. Quant j'attend juste la conclusion après 30 000 boucle je cale 1ms voir pas de délai du tout histoire d'abreger le truc. C'est du séquentielle donc pas de soucis d’exécution c'est du step by step. Ce qui peut permettre un point d'ancrage pour le timer (si c'est possible) c'est d'utiliser la variable ncycle qui incrémente de +1 a chaque fin de boucle.

    je vais creuser ta proposition je pense que c'est pas loin de ce que je cherche

    merci bien

  12. #12
    Membre du Club
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Octobre 2015
    Messages
    98
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Santé

    Informations forums :
    Inscription : Octobre 2015
    Messages : 98
    Points : 59
    Points
    59
    Par défaut
    J'ai tester le timer. C'est top.

    le timer.interval me pose soucis. Sauf a bricoler un truc pour que ma variable "int cycle" incrémenter (dans la méthode situé dans le thread en plus) soit sorti de la méthode, comparer a la valeur précédente de "cycle" et trafiquer la methode pour faire croire que la minuterie vient de prend +1 je voit pas très bien la façon de créer mon propre timer calé sur le nombre de boucle (mon référentiel temporel) et non pas sur le temps réel écoulé.

    Est-ce que un "design observateur" ne serait pas une solution plus intéressante ?

  13. #13
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    je ne comprends pas trop ce que tu racontes

    le timer a un interval, à la fin de l'exécution du code contenu il compte pour se redéclencher (à vérifier que si tu dépasses le temps d'interval ca attend quand même plutot que de relancer dans la foulée pensant que le temps est écoulé)
    si tu veux ne le faire que x fois, alors tu mets un compteur dans ta classe, et dans le tick après avoir fait +1 si le compteur dépasse tu arrêtes le timer
    et tu peux aussi modifier l'interval pendant que ca tourne
    de plus le timer est censé te dispenser d'une boucle

    si tu veux compter le temps d'exécution entre 2 points il y a le system.diagnostics.stopwatch (chronomètre ; .Start, .Stop, .ElapsedMillseconds)

    sinon le timer.interval et le thread.sleep sont en millisecondes, donc 3 secondes ca fait 3000, pas 300

    avec la solution du thread tu n'est pas obligé de t'embeter avec des invokes, si tu remplies des variables de classe (aucun soucis depuis n'importe quel thread), un timer peut alors lire ces variables et afficher les données sur la fenetre de manière désynchronisée (quitte à avoir un timer assez rapide de l'ordre de la demie seconde)

    le pattern observer c'est un peu comme un event, c'est quand tu modifies un truc ceux que ça intéressent sont avertis, je ne vois pas trop le rapport ici
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  14. #14
    Membre du Club
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Octobre 2015
    Messages
    98
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Santé

    Informations forums :
    Inscription : Octobre 2015
    Messages : 98
    Points : 59
    Points
    59
    Par défaut
    Autemps pour moi. Donc avec timer j'obtiend ceci:

    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
     
    bool test = true;        
    int ncycle = 0;        
    string Presentation;
     
            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
     
                //  DispatcherTimer setup
                DispatcherTimer loulou = new DispatcherTimer();
                loulou.Tick += new EventHandler(dispatcherTimer_Tick);
                loulou.Interval = new TimeSpan(0, 0, 1);
                loulou.Start();
     
     
                // Déclaration du thread
                Thread mytread;         
                mytread = new Thread(Debut);
                // Lancement du thread
                mytread.Start();           
            }
     
            private void dispatcherTimer_Tick(object sender, EventArgs e)
            {           
                //labeltest.Content = DateTime.Now.Second;
                labeltest.Content = ncycle;
                tb1.Text = Presentation;
     
                CommandManager.InvalidateRequerySuggested();
            }
     
            public void Debut()
            {
                // Tant que le thread n'est pas tué, on travaille
                while (ncycle <20)
                //while (Thread.CurrentThread.IsAlive)
                {
                    if (test == true)
                    {
                        // Wait for 3sec
                        Thread.Sleep(300);
     
                        Presentation = "VALEUR A";
     
                        toto.Dispatcher.Invoke(
                        System.Windows.Threading.DispatcherPriority.Normal,
                        new Action(
                        delegate ()
                        {
                            toto.Text = Presentation;
                        }
                        ));
                        test = false;
                        ncycle++;
                    }
                    else
                    {
                        Thread.Sleep(300);
     
                        Presentation = "B Valeur";
     
                        toto.Dispatcher.Invoke(
                        System.Windows.Threading.DispatcherPriority.Normal,
                        new Action(
                        delegate ()
                        {
                            toto.Text = Presentation;
                        }
                        ));
                        test = true;
                    }
                }
            }

    La seul chose qui me pose soucis c'est que le temps réel ne m’intéresse pas. Je veut que le timer se cale sur ma boucle. A chaque fois que la variable int ncycle incrémente de +1 il me rend compte et pas a chaque X seconde.
    Après effectivement dans le processus si je pouvais être certain que la boucle est terminé et qu'il ne m'affiche pas un truc intermédiaire ça m'arrangerai. La encore je veut pas avoir à jouer avec les milliseconde du temps de traitement. Si il faut 3ms pour faire la boucle tend mieux, si il faut 30 sec je m'en fou. Affichage uniquement a la fin de la boucle.
    Je pense que c'est sur le loulou.Interval = new TimeSpan(0, 0, 1); qu'il y'a un truc a modifier non ?

  15. #15
    Expert confirmé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2009
    Messages
    2 025
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Novembre 2009
    Messages : 2 025
    Points : 5 462
    Points
    5 462
    Par défaut
    Citation Envoyé par pyriame Voir le message
    Je veut que le timer se cale sur ma boucle. A chaque fois que la variable int ncycle incrémente de +1 il me rend compte et pas a chaque X seconde.
    Ce n'est donc pas un timer que tu veux .
    Tu peux regarder du coté du BackgroundWorker, qui comme son nom l'indique fait un travail en arriere plan.
    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
    32
     
      private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                BackgroundWorker bw = new BackgroundWorker();
                bw.DoWork += Bw_DoWork;
                bw.RunWorkerCompleted += Bw_RunWorkerCompleted;
                bw.ProgressChanged += Bw_ProgressChanged; 
                bw.RunWorkerAsync();
            }
     
            private void Bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
            {
                labeltest.Content = ncycle;
                tb1.Text = Presentation;
            }
     
            private void Bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
            {
                MessageBox.Show("J'ai fini !!!!!!");
            }
     
            private void Bw_DoWork(object sender, DoWorkEventArgs e)
            {
                BackgroundWorker worker = sender as BackgroundWorker;
                while (testeur > 0)
                {
                    debut();
                    Fin();
                    ncycle++;
                    worker.ReportProgress(100/* un eventuel calcul du % realisé **/, null); 
                }
            }
    Tu peux passer le worker à tes fonction debut et fin si tu veux signaler un ReportProgress à l'interieur de ces methodes.

  16. #16
    Membre du Club
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Octobre 2015
    Messages
    98
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Santé

    Informations forums :
    Inscription : Octobre 2015
    Messages : 98
    Points : 59
    Points
    59
    Par défaut
    Bonsoir,
    effectivement le backgroundworker me va bien.
    J'ai enfin compris le fonctionnement ou, en partie en tous, cas la logique.

    Je suis presque au bout. Voici mon code:

    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
     
    public partial class MainWindow : Window
        {       
            private BackgroundWorker backgroundWorker;
            double AAA = 123;
            string BBB = "hello";
            bool CCC = true;
            int cycle = 0;
     
            public MainWindow()
            {
                InitializeComponent();            
            }        
     
            private void Window_Loaded(object sender, RoutedEventArgs e)
            {            
                List<object> LaListe = new List<object>();
                LaListe.Add(AAA);
                LaListe.Add(BBB);
                LaListe.Add(CCC);
     
     
                backgroundWorker = new BackgroundWorker();
                backgroundWorker.DoWork += BackgroundWorkerDoWork;
                backgroundWorker.ProgressChanged += BackgroundWorkerProgressChanged;
                backgroundWorker.RunWorkerCompleted += BackgroundWorkerRunWorkerCompleted;
     
                backgroundWorker.RunWorkerAsync(LaListe);
            }
     
            private void BtnActionClick(object sender, RoutedEventArgs e)
            {           
                backgroundWorker.CancelAsync();
            }
     
            void BackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
            {           
                List<object> genericlist = e.Argument as List<object>;
     
                while (cycle < 10)
                {
     
                    AAA = (double)genericlist[0];
                    BBB = (string)genericlist[1];
                    CCC = (bool)genericlist[2];
     
                    ///int AAA = (int)e.Argument;   // the 'argument' parameter resurfaces here
     
                    // and to transport a result back to the main thread
                    genericlist[0] = 0.1 * AAA;
                    genericlist[1] = BBB + "yeah";
                    genericlist[2] = CCC;
     
                    Thread.Sleep(500);
                    cycle++;
                    e.Result = genericlist;               
                }
                e.Result = genericlist;            
            }
     
            void BackgroundWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
            {
                //double result = (double)e.Result[0];
                List<object> result = e.Result as List<object>;            
                toto.Text = Convert.ToString(result[0]);
                label12.Content = result[1];
            }
     
            void BackgroundWorkerProgressChanged(object sender, ProgressChangedEventArgs e)
            {
                //double result = (double)e.Result[0];
                List<object> userstate = e.UserState as List<object>;
                toto.Text = Convert.ToString(userstate[0]);
                label12.Content = userstate[1];           
            }       
        }
    Donc dans l'idée j'ai un paquet de variable AAA, BBB, CCC, etc... qui vont interagir dans mon Dowork.

    - la list<objet> me semble un peu fastidieuse à coder, une méthode serait peut être plus simple.

    - J'ai toujours mon problème de boucle c'est a dire que le while (cycle <10) est juste la pour l'exemple mais en pratique le nombre de boucle sera plutôt de l'ordre de 300 000 et je voit bien que mes résultats sont mise a jour uniquement a la fin de toute les boucle ce qui de ce que je comprend est normal puisqu'on appelle BackgroundWorkerRunWorkerCompleted, mais qui ne me va pas puisque je cherche un affichage a chaque fin de boucle.

    -j'ai donc voulu utiliser BackgroundWorkerProgressChanged qui correspond a ce que je veut mais qui ne sort que des "int" et pas l'objet en entier (quel co***rie...).

    -visiblement les variables sont bien mise a jour a chaque boucle vu le résultat final mais je ne comprend pas réellement pourquoi et ou a quel moment ça se passe.


    voila j'avance petit a petit

  17. #17
    Membre du Club
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Octobre 2015
    Messages
    98
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Santé

    Informations forums :
    Inscription : Octobre 2015
    Messages : 98
    Points : 59
    Points
    59
    Par défaut
    Bon ça rentre doucement.
    Voila le code final qui fonctionne.
    -Mise a jour après chaque boucle des variables puis réutilisation dans la boucle.
    -Affichage après chaque fin boucle des variables.
    -une méthode isolé du reste pour faire le process long qui auparavant était en console.

    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
     
    public partial class MainWindow : Window
        {       
            private BackgroundWorker backgroundWorker;
            double AAA = 123;
            string BBB = "hello";
            bool CCC = true;
            int cycle = 0;
     
            public MainWindow()
            {
                InitializeComponent();            
            }        
     
            private void Window_Loaded(object sender, RoutedEventArgs e)
            {            
                List<object> LaListe = new List<object>();
                LaListe.Add(AAA);
                LaListe.Add(BBB);
                LaListe.Add(CCC);
     
                backgroundWorker = new BackgroundWorker();
                backgroundWorker.DoWork += BackgroundWorkerDoWork;
                backgroundWorker.RunWorkerCompleted += BackgroundWorkerRunWorkerCompleted;
     
                backgroundWorker.RunWorkerAsync(LaListe);            
            }
     
            private void BtnActionClick(object sender, RoutedEventArgs e)
            {           
                backgroundWorker.CancelAsync();
            }
     
            void BackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
            {
                while (cycle < 10)
                {                              
                    //AAA = 0.1 * AAA;
                    //BBB = BBB + "yeah";
     
                    proc_test();
     
                    Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(
                            delegate ()
                            {
                                toto.Text = Convert.ToString(AAA);
                                label12.Content = BBB;
                                labeltest.Content = cycle;
                            }));
                    Thread.Sleep(500);
                    cycle++;
                }
                List<object> genericlist = e.Argument as List<object>;
                e.Result = genericlist;            
            }
     
            void BackgroundWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
            {
                List<object> result = e.Result as List<object>;            
                toto.Text = Convert.ToString(result[0]);
                label12.Content = result[1];
                labeltest.Content = cycle;
            }
     
            void proc_test()
            {
                //methode qui contiend tous le process lourd
                AAA = 0.1 * AAA;
                BBB = BBB + "yeah";
            }
        }
    -La création de la liste d'objet n'est pas indispensable mais elle me permet de conclure en fin de while proprement mais je pourrait mettre un "merde" "gameover" ou "loose" sa reviendrai au même. Si je sort de la boucle c'est que le process long ne marche pas. je le remplacerai plus tard avec la constante qui va bien.


    J'aurais une dernière question: peut on ajouter grâce a un bouton une "pause" dans le process long ? Une chose que je n'avait pas sur mon mode console c'est la possibilité de figer le process long, regarder les dernières variable afficher , puis reprendre le process? Encore une fois pas en milieu de boucle, juste a la fin c'est a dire que l'appel a la pause par un clic bouton fige le truc mais laisse d'abord se terminer le process long comme ça toute mes variables sont mise a jour. Je cherche de mon coté évidement

    encore merci de votre aide

  18. #18
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    manualresetevent je pense, avec un booléen peut etre

    sinon cancel il ne suffit pas de l'appeler, ca ne fait que setter un booléen à true
    c'est à toi de vérifier dans dowork à chaque tour si cancellationpending = true, auquel cas tu fais ce qu'il faut pour sortir proprement de la boucle et de l'event dowork
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  19. #19
    Expert confirmé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2009
    Messages
    2 025
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Novembre 2009
    Messages : 2 025
    Points : 5 462
    Points
    5 462
    Par défaut
    Tu ne devrais pas avoir à utiliser le dispatcher dans le background worker, c'est d'ailleurs un peu son avantage .
    Tu ne fais aucun appel à worker.ReportProgress et donc BackgroundWorkerProgressChanged n'est pas appelé.
    Si ca te gene de passer par une list<objet>, ce qui est effectivement peu pratique, créé toi un objet bien à toi avec les propriétés que tu souhaites.

    Pour la pause c'est très simple, tu mets à l'interieur de ta boucle une condition sur une variable de ta classe
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    while (cycle < 10)
                {
                    if(!pause)
                    {
                        //blablablblablal
                        worker.ReportProgress(100/* un eventuel calcul du % realisé **/, unObjetQuiContientToutCeQueTuVeux);
     
                    }
     
                }
    Il te suffit de gérer ce booleen ailleurs sur des actions de ta fenetre.

  20. #20
    Membre du Club
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Octobre 2015
    Messages
    98
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Santé

    Informations forums :
    Inscription : Octobre 2015
    Messages : 98
    Points : 59
    Points
    59
    Par défaut
    Bonsoir,
    A y'est c'est bon. je devrais pouvoir rapatrier mon programme console dans une appli WPF !!!!
    J'ai donc 3 boutons pour mon process long: Start, Stop et Pause/Resume.

    Voici le code qui est fonctionnelle:
    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
     
     public partial class MainWindow : Window
        {       
            private BackgroundWorker backgroundWorker;
            double AAA = 123;
            string BBB = "hello";
            bool CCC = true;
            int cycle = 0;
     
            ManualResetEvent _busy = new ManualResetEvent(true);
     
            public MainWindow()
            {
                InitializeComponent();            
            }        
     
            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                backgroundWorker = new BackgroundWorker();
                backgroundWorker.DoWork += BackgroundWorkerDoWork;
                backgroundWorker.RunWorkerCompleted += BackgroundWorkerRunWorkerCompleted;
            }
     
            void BackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
            {
                while (cycle < 20)
                {
                    _busy.WaitOne(Timeout.Infinite);
                    // _busy.WaitOne(Timeout.Infinite);
                    proc_test();
     
                            Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(
                                    delegate ()
                                    {
                                        toto.Text = Convert.ToString(AAA);
                                        label12.Content = BBB;
                                        labeltest.Content = cycle;
                                    }));
                            Thread.Sleep(500);
                            cycle++;
                    //_busy.WaitOne(Timeout.Infinite);
                }
     
                List<object> genericlist = new List<object>();
                genericlist.Add(AAA);
                genericlist.Add(BBB);
                genericlist.Add(CCC);
                e.Result = genericlist;
            }
     
            void BackgroundWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
            {
                List<object> result = e.Result as List<object>;            
                toto.Text = Convert.ToString(result[0]);
                label12.Content = result[1];
                labeltest.Content = cycle;
            }
     
            void proc_test()
            {
                //methode qui contiend tous le process lourd
                AAA = 0.1 * AAA;
                BBB = BBB + "yeah";
            }
     
            private void BtnLancer(object sender, RoutedEventArgs e) // Lance process long
            {
                if (!this.backgroundWorker.IsBusy)
                    this.backgroundWorker.RunWorkerAsync();               
            }
     
            private void BtnPause(object sender, RoutedEventArgs e) // met en Pause et relance process long
            {
                if (bt1.Content.ToString() == "PAUSE")
                {
                    _busy.Reset();
                    bt1.Content = "RESUME";
                }
                else
                {
                    _busy.Set();
                    bt1.Content = "PAUSE";
                }
            }
     
            private void Btnstop(object sender, RoutedEventArgs e) // stop process long
            {
                //if (this.backgroundWorker.IsBusy)
                //this.backgroundWorker.CancelAsync();
                _busy.Reset();
            }
        }
    J'ai quelques petite questions purement techniques histoire de comprendre un peu mieux ce que je fait.

    - une différence entre : _busy.WaitOne(Timeout.Infinite) et _busy.WaitOne(); ?

    - Quel différence entre : this.backgroundWorker.CancelAsync() et _busy.Reset() ? Si je met que le CancelAsync je ne peut pas fermer ma fenêtre autrement que via visualstudio alors qu'avec busyreset je peut cliquer sur la croix en haut a droite de la fenêtre. Seulement le busy.reset qui semble être une "pause" me gène dans le sens ou si c'est pour consommer des ressources alors que si j'appui sur STOP c'est pour arrêter définitivement (sinon j'aurais fait pause...) je voit pas très bien l’intérêt. Y'a t'il une solution d’arrêt "PROPRE" qui redonne la main sur le thread principal sans arrêt brutal du process long ?

    -j'ai un doute sur le positionnement du _busy.WaitOne() dans la boucle. Plutôt en début ou enfin ?

    -Enfin est ce que sur ce code et en imaginant un thread trèeeessss long il y'a un risque de plantage ou de désynchronisation si le temps de traitement dépasse le Thread.Sleep(500) de ma boucle? Genre il m'affiche la 43eme boucle alors qu'on est a la 650ème? Comme mes variables de sortis en fin de boucle sont les variable d'entré dans la boucle suivante je voudrais être sure que le multithread rendent pas tous le processus complètement instable.

    encore merci de votre aide.

    bonne nuit

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

Discussions similaires

  1. [MVVM] Question générale sur portage WinForms vers WPF
    Par moulefrite dans le forum Windows Presentation Foundation
    Réponses: 11
    Dernier message: 15/01/2016, 07h18
  2. Portages d'une application en console vers des fenêtres
    Par mess-mate dans le forum wxWidgets
    Réponses: 8
    Dernier message: 08/10/2008, 20h27
  3. Réponses: 13
    Dernier message: 06/09/2007, 06h50
  4. Problème portage Delphi3 vers Delphi7
    Par bob1980 dans le forum EDI
    Réponses: 5
    Dernier message: 30/11/2005, 17h47
  5. Programmer une boucle de saisie chaine de caractère.
    Par Spike Spiegel dans le forum C
    Réponses: 30
    Dernier message: 02/10/2005, 17h46

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