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 :

Remplissage treeview depuis un backgroundworker


Sujet :

Windows Forms

  1. #1
    Membre chevronné Avatar de petitours
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Février 2003
    Messages
    1 935
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2003
    Messages : 1 935
    Points : 2 013
    Points
    2 013
    Par défaut Remplissage treeview depuis un backgroundworker
    Bonjour

    Mon appli charge dans des grosses Liste le contenu de fichiers CSV très gros (plusieurs 100n de Mo). EN même temps, cela ajoute des noeuds dans un treeview pour lister les champs du fichiers CSV.

    Cela fonctionne très bien mis à part que ça freeze mon appli pendant de très longues secondes.
    Le freeze n'est pas spécialement un soucis puisque je n'ai rien d'autre à faire que charger le fichier mais je souhaite ajouter un progressBar pour me dire où j'en suis et voir que l'appli n'est pas plantée...donc mise en place d'un backgroundworker.

    Là ça coince parce que le progressbar ne se met pas à jour dans le ProgressChanged à cause des modifications de treeview dans le DoWork.
    Bref, puisque j'accède au treeview depuis le second thread cela freeze de la même manière mon ihm !

    J'ai trouvé les Invoke mais c'est super compliqué, je n'arrive rien à comprendre aux syntaxes des délégués et de leur appel... et je me dis que finalement pour un simple progressBar c'est bien compliqué !

    Si le DoWork d'un backgroundworker doit remplir un treeview à partir d'un fichier, est il possible de mettre à jour l'affichage du treeview qu'une fois la lecture du fichier terminée afin de ne pas bloquer le thread principal ?
    Avec quelquechose comme un treeview.update() une fois arrivé dans le RunWorkerCompleted peut être ?

    Merci par avance pour vos conseils.
    Il y a 10 sortes de personnes dans le monde : ceux qui comprennent le binaire et les autres

  2. #2
    Membre chevronné
    Avatar de PixelJuice
    Homme Profil pro
    Ingénieur .NET & Game Designer
    Inscrit en
    Janvier 2014
    Messages
    640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Ingénieur .NET & Game Designer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2014
    Messages : 640
    Points : 2 149
    Points
    2 149
    Par défaut
    Je t'avouerai que j'étais aussi perdu quand j'ai du me confronter aux delegates / invoke / etc , et après avoir vu des tas d'exemples très compliqué pour rien , voici une petite astuce qui t'aidera j'espere :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    this.Invoke(new MethodInvoker(delegate { TextBox1.Text = "Test"; }));
    Cela permet d'accéder a tes contrôles et a agir sur eux dans ta méthode du BackGroundWorker (ou d'un thread).

    Dans ton cas , tu pourrais récupérer des infos de ton TreeView.

  3. #3
    Invité
    Invité(e)
    Par défaut
    Dans le Framework .NET 4.5, les mots clés "async" et "await" ont été mis en place exactement dans ce but : que lors d'un chargement qui prend du temps l'IHM ne fige pas.

    BackgroundWorker est devenue une antiquité maintenant! et oui, avant c'était compliqué, je confirme.

    Pour plus d'information sur l'utilisation de "await" et "async" voir ici :
    http://msdn.microsoft.com/en-us/libr.../hh191443.aspx

    si tu n'es pas à l'aise avec l'anglais remplace "en-us" par "fr-fr" dans l'url ci-dessus, mais je ne le conseille pas car ça a été traduit par un outil automatique qui n'a pas toujours très bien traduit...

    L'idéal dans ton cas est d'utiliser le "Task-based Asynchronous Pattern" (TAP), c'est à dire que tu as une méthode qui te renvoie un objet "Task" et qui admet en paramètre un jeton d'annulation et un objet "IProgress" qui va justement te permettre d'indiquer la progression.

    Voir l'URL suivante pour le TAP :
    http://msdn.microsoft.com/en-us/libr.../hh873175.aspx

    D'autre part, en ce qui concerne le remplissage de ton treeview, étant donné que tu ne peux pas le remplir ailleurs que sur le thread de l'IHM (pour rappel, un élément d'IHM ne doit jamais être utilisé en dehors du thread principal) tu as 2 possibilités :
    1) Dans ton paramètre générique du paramètre "IProgress", tu inclus en plus une information indiquant qu'est-ce que tu vas mettre à ce moment là.
    2) Tu remplis tout d'abord un objet d'une classe que tu crée. A la fin du remplissage, comme tout est chargé en mémoire (et 100Mo ce n'est pas si gros que ça donc ça peut être chargé en mémoire) tu n'as plus qu'à transférer ce qu'il faut depuis ta structure vers ton TreeView sur le thread de l'IHM (ça doit être assez rapide à ce moment-là normalement)
    Dernière modification par Invité ; 28/01/2014 à 09h29.

  4. #4
    Membre chevronné Avatar de petitours
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Février 2003
    Messages
    1 935
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2003
    Messages : 1 935
    Points : 2 013
    Points
    2 013
    Par défaut
    Bonjour

    Ça fait plusieurs jours que je tente des essais de TAP et rien... je n'y comprends rien du tout l'anglais n'est certes pas mon fort mais il n'y a pas que ça, je suis méchamment fâché avec la syntaxe du truc !
    C'est vraiment sensé être plus simple que le backgroundworker ?
    Il y a 10 sortes de personnes dans le monde : ceux qui comprennent le binaire et les autres

  5. #5
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par petitours Voir le message
    Bonjour

    Ça fait plusieurs jours que je tente des essais de TAP et rien... je n'y comprends rien du tout l'anglais n'est certes pas mon fort mais il n'y a pas que ça, je suis méchamment fâché avec la syntaxe du truc !
    C'est vraiment sensé être plus simple que le backgroundworker ?
    Bonjour,

    Oui, c'est largement plus simple que le backgroundworker.
    Peux-tu me montrer ce que tu as essayé pour que je comprennes pourquoi tu t'y casses les dents?

  6. #6
    Membre chevronné Avatar de petitours
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Février 2003
    Messages
    1 935
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2003
    Messages : 1 935
    Points : 2 013
    Points
    2 013
    Par défaut
    Bonjour

    voici l'exemple le plus simple que j'ai tenté
    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
    private void btTestAsync_Click(object sender, EventArgs e)
            {
                await TestAsync();
     
              /* ecriture longue
                Task testTask = TestAsync();
                await testTask;
                */
            }
     
            async Task TestAsync()
            {
                System.Threading.Thread.Sleep(7000);
     
                toolStripStatusLabel1.Text = "Hello world";
            }
    test basé sur le peu que je comprends de cette page
    http://msdn.microsoft.com/en-us/libr.../hh191443.aspx

    J'ai tenté un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
            private void btTestAsync_Click(object sender, EventArgs e)
            {
                TestAsync();
            }
     
            async Task TestAsync() 
            {
                Task TestTask = System.Threading.Thread.Sleep(7000);
                await TestTask ;
     
                toolStripStatusLabel1.Text = "Hello world";
            }
    aussi

    alors je lis que seules certaines méthodes acceptent le async ca expliquerait pourquoi ça ne marche pas là. Mais en même temps les exemples qu'ils donnent sont sur des fonctions "à eux", donc pas des méthodes C# qui gèreraient le async.

    J'ai bien conscience d’être à la ramasse totale... le truc c'est que je n'arrive pas du tout à piger la logique du truc !
    Il y a 10 sortes de personnes dans le monde : ceux qui comprennent le binaire et les autres

  7. #7
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    En fait cet exemple que tu m'a montré :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    async Task TestAsync()
    {
    	System.Threading.Thread.Sleep(7000);
     
    	toolStripStatusLabel1.Text = "Hello world";
    }
    a du te mettre un warning et en plus, à l'exécution, ça fige l'IHM pendant 7 secondes.

    Quant à celui-ci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    async Task TestAsync() 
    {
    	Task TestTask = System.Threading.Thread.Sleep(7000);
    	await TestTask ;
     
    	toolStripStatusLabel1.Text = "Hello world";
    }
    il ne compile pas car "Sleep" ne renvoie pas un objet de type "Task".

    Il faut aussi que tu lises la doc sur la classe "Task" elle-même, pour voir comment on l'utilise, c'est pour cela que tu ne piges pas.

    Ton exemple aurais pu être remplacé par:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    async Task TestAsync() 
    {
    	Task TestTask = Task.Run(()=> System.Threading.Thread.Sleep(7000));
    	await TestTask ;
     
    	toolStripStatusLabel1.Text = "Hello world";
    }
    mais là on se complique la vie.

    Si tu avais lu la doc de la classe "Task" tu aurais vu que ça aurait pu être remplacé par :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    async Task TestAsync() 
    {
    	await Task.Delay(7000);
    	toolStripStatusLabel1.Text = "Hello world";
    }
    Dans ce cas là, l'IHM sera bien utilisable pendant la phase de délai puis va afficher le fameux "Hello world".
    Alors là, petit truc étrange : alors que dans la méthode "TestAsync" renvoie un "Task" et qu'on a fait aucun "return" de qqch, le compilateur est quand même content. C'est parce qu'en fait, dès qu'il y a un async à la méthode et au moins un "await", une tâche est bien renvoyée.
    D'ailleurs ça peut être même plusieurs "await" :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    async Task TestAsync() 
    {
    	await Task.Delay(2000);
    	toolStripStatusLabel1.Text = "Hello world";
            await Task.Delay(2000);
    	toolStripStatusLabel1.Text = "Hello world 2";
    }
    C'est dans ce cas comme une continuation de tâches qui switchent à chaque fois entre contexte non-IHM puis contexte IHM. ça évite de faire appel à des "Control.Invoke" intempestifs.

    C'est vrai que ce n'est peut-être pas facile à comprendre au premier abord mais une fois que tu as eu le déclic, tu verras que ça te faciliteras la vie, le problème de toujours étant, comme je l'ai déjà dit, qu'il n'est pas possible de manipuler un élément d'IHM dans un thread qui n'est pas le thread de l'IHM.

  8. #8
    Membre chevronné Avatar de petitours
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Février 2003
    Messages
    1 935
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2003
    Messages : 1 935
    Points : 2 013
    Points
    2 013
    Par défaut
    Oh .utain

    Clur que c'est super puissant le truc !

    Bon en fait ce que je vois c’est que je me suis tiré une balle dans le pied avec mon test en prenant une pose sur un thread ou il n'y a pas de méthode async...
    J'aurais sans doute mieux fait de bosser avec un stremReader qui semble avec plusieurs trucs en async et en ce qui me concerne c'est surtout sur des lectures et écritures de très gros fichiers que j'ai besoin de ça.

    Là j'arrive à faire tourner le truc !

    J'ai lu que quand la fonction async ne renvoi rien il fallait mettre Task tout seul sans <>...me souviens plus où mais je jurerais l'avoir lu


    Me reste deux soucis
    1) que je vais peut être réussir à éclairer tout seul maintenant que le async de base est bien plus clair : comment gérer le retour de progrès de la tache asynchrone, typiquement faire avancer un progressBar au fur et à mesure qu'un fichier est lu dans mon cas.
    Je suis tombé là dessus
    http://msdn.microsoft.com/fr-fr/libr.../br206581.aspx
    et j'ai fait une syncope en regardant cette syntaxe encore nouvelle... C'est le bon endroit où regarder ?

    2) Pour exécuter sans figer l'IHM une fonction du genre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ZipFile.CreateFromDirectory(CheminRepertoireDepart, CheminFinal);
    qui prend 30bonnes secondes à l’exécution.
    -Puis je gérer un async avec ce genre de tache qui n'a pas de méthode async ?
    -Faut il que je reste avec un backgroundworker dans ce cas là ?
    -Ai je vrai en pensant que je n'ai aucun moyen de gérer un avancement (progressBar...) sur l’exécution de ce long zipage qui tient en une seule ligne ?

    Merci beaucoup
    Il y a 10 sortes de personnes dans le monde : ceux qui comprennent le binaire et les autres

  9. #9
    Membre chevronné Avatar de petitours
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Février 2003
    Messages
    1 935
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2003
    Messages : 1 935
    Points : 2 013
    Points
    2 013
    Par défaut
    Euh , pour gérer un progressBar sur la lecture d'un gros fichier il suffit juste de gérer en Async la lectures des lignes et de prévoir une boucle toute bête qui va mettre à jour le progressBar, non ?
    Pas besoin de syntaxes particulières ?
    S ? ce serait plus rapide avec une syntaxe particulière ?
    Il y a 10 sortes de personnes dans le monde : ceux qui comprennent le binaire et les autres

  10. #10
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par petitours Voir le message
    J'ai lu que quand la fonction async ne renvoi rien il fallait mettre Task tout seul sans <>...me souviens plus où mais je jurerais l'avoir lu
    En effet, c'était bien écrit, tu n'as pas rêvé. Mais ce n'est pas toujours possible comme par exemple avec les "handlers" d'événements et les "override".


    Citation Envoyé par petitours Voir le message
    Me reste deux soucis
    1) que je vais peut être réussir à éclairer tout seul maintenant que le async de base est bien plus clair : comment gérer le retour de progrès de la tache asynchrone, typiquement faire avancer un progressBar au fur et à mesure qu'un fichier est lu dans mon cas.
    Je suis tombé là dessus
    http://msdn.microsoft.com/fr-fr/libr.../br206581.aspx
    et j'ai fait une syncope en regardant cette syntaxe encore nouvelle... C'est le bon endroit où regarder ?
    Non pas du tout pour ton cas, cette doc concerne uniquement une spécificité du Windows Runtime, càd les applications du Windows Store.
    L'URL que je t'avais montré à l'origine était :
    http://msdn.microsoft.com/en-us/libr.../hh873175.aspx

    Regarde en particulier l'interface générique "IProgress" et son implémentation par défaut dans la classe "Progress".

    Citation Envoyé par petitours Voir le message
    2) Pour exécuter sans figer l'IHM une fonction du genre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ZipFile.CreateFromDirectory(CheminRepertoireDepart, CheminFinal);
    qui prend 30bonnes secondes à l’exécution.
    -Puis je gérer un async avec ce genre de tache qui n'a pas de méthode async ?
    -Faut il que je reste avec un backgroundworker dans ce cas là ?
    -Ai je vrai en pensant que je n'ai aucun moyen de gérer un avancement (progressBar...) sur l’exécution de ce long zipage qui tient en une seule ligne ?
    Ah, tu utilises une classe externe qui ne fournit pas d'implémentation de cette méthode avec le pattern TAP.
    Au pire tu peux, pendant ce temps, mettre une barre de progression "indéterminée".
    ça donnerait quelque chose comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Task async CreateFromDirectoryAsync(string cheminRepDepart, string cheminFinal)
    {
        return Task.Factory.StartNew(()=>CreateFromDirectory(cheminRepDepart,cheminFinal));
    }
    et après tu peux faire un await dessus :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    ...
    try { await CreateFromDirectoryAsync(cheminRepDepart, cheminFinal); }
    catch(Exception exc) { ... }
    ...
    Sinon, dans tous les cas, à ta place je ne resterais surement pas avec un backgroundworker, mais bon c'est toi qui voit.

    PS : au fait, j'espère que tu maîtrises bien les expressions lambda, c'est indispensable!

  11. #11
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par petitours Voir le message
    Euh , pour gérer un progressBar sur la lecture d'un gros fichier il suffit juste de gérer en Async la lectures des lignes et de prévoir une boucle toute bête qui va mettre à jour le progressBar, non ?
    Pas besoin de syntaxes particulières ?
    S ? ce serait plus rapide avec une syntaxe particulière ?
    Je vois, tu voudrais faire un truc du genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    ...
    for(int i=0;i<MAX;i++)
    {
       var maLigne = await LitLigneAsync();
       monControl.RemplitIHM(maLigne);
    }
    ...
    Tu pourrais, oui, mais ce serait peut-être moins efficace qu'en passant un paramètre "IProgress" car avec un paramètre "IProgress" il n'y aurait qu'une seule tâche qui tourne... Mais cela dit je n'en suis pas certain...

  12. #12
    Membre chevronné Avatar de petitours
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Février 2003
    Messages
    1 935
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2003
    Messages : 1 935
    Points : 2 013
    Points
    2 013
    Par défaut
    Je maitrise rien... Pour les expression lambda, je viens de découvrir que le "=>" que je ne comprends pas dans l'exemple ci dessus en est une... je vais creuser ça. Ça a l'air d’écrire en une ligne ce que j'aurais mis en 10, ça me plait !

    Perso je viens du C sur microcontrôleur, c'est bien plus puissant que l'assembleur sur microcontrôleur mais à des années lumières du C#.net...
    Dit autrement je comprends vite mais il faut m'expliquer doucement !

    Je ne dors pas tant que mon appli n'est pas fluide et que je n'ai pas un progressBar sur la lecture de mes fichiers !!

    Merci
    Il y a 10 sortes de personnes dans le monde : ceux qui comprennent le binaire et les autres

  13. #13
    Membre expérimenté Avatar de callo
    Homme Profil pro
    Administrateur systèmes et réseaux
    Inscrit en
    Février 2004
    Messages
    887
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Togo

    Informations professionnelles :
    Activité : Administrateur systèmes et réseaux
    Secteur : Service public

    Informations forums :
    Inscription : Février 2004
    Messages : 887
    Points : 1 699
    Points
    1 699
    Par défaut
    Bonsoir,
    Pour gérer le progressbar, regarde ce tuto. Effectivement, il faut passer par IProgress.
    N'oubliez pas le tag et

  14. #14
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par petitours Voir le message
    Je maitrise rien... Pour les expression lambda, je viens de découvrir que le "=>" que je ne comprends pas dans l'exemple ci dessus en est une... je vais creuser ça. Ça a l'air d’écrire en une ligne ce que j'aurais mis en 10, ça me plait !

    Perso je viens du C sur microcontrôleur, c'est bien plus puissant que l'assembleur sur microcontrôleur mais à des années lumières du C#.net...
    Dit autrement je comprends vite mais il faut m'expliquer doucement !

    Je ne dors pas tant que mon appli n'est pas fluide et que je n'ai pas un progressBar sur la lecture de mes fichiers !!

    Merci
    Ah OK.

    Alors pour tout ce qui est expression lambda et délégués, en fait pour expliquer simplement, ce sont des méthodes créées à la volée dans le code où tu te trouves, autrement dit tu peux déclarer une méthode dans une méthode en .NET!
    Cette méthode déclarée à la volée a une signature qui sont souvent des "Action" ou des "Func", mais ça peut être aussi une signature que tu déclares.

    Exemple :
    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
     
    void TestLambda()
    {
       int variableDeContexte = 5;
       Action action = () => { int i=0; i++ };
       Func<int> fct1 = () =>
       {
           Random rd = new Random();
           return rd.Next(variableDeContexte++ ,10); //et on a même accès à la variable définie un niveau au-dessus et la modifier!
       }
       Func<int,int> fct2 = i => 2*i; //Pourrait être écrite aussi : Func<int,int> fct2 = i => { return 2*i; };
     
       //On peut après les appeler
       int test1 = fct1();
    }
    Voilà pour une petite intro, après documentes-toi dessus aussi.

  15. #15
    Membre chevronné Avatar de petitours
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Février 2003
    Messages
    1 935
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2003
    Messages : 1 935
    Points : 2 013
    Points
    2 013
    Par défaut
    Bon je me fais fumer les neurones ! autant les async je ne pigeais pas la syntaxe mais je savais à quoi ça pouvait servir, autant les lambda et les delegate ça associe le mystère de la syntaxe et un niveau d'abstraction qui me dépasse encore , rien que pour en comprendre l’intérêt je ne suis pas sorti !
    Bref pas grave ca va venir...

    Pour ce qui en est de Iprogress, si je comprends bien c'est, au même titre que l'annulation, une surcharge possible pour les méthodes Async qui sont gérée sur certaines taches très longues.

    Dans mon cas j'ai l'impression que ca ne conviendrait pas parce que ce qui est long dans mon cas est
    soit le zipage évoqué tout à l'heure
    qui dure 30s mais qui ne gère pas de méthodes async :-(

    Soit des boucles très longues. en voici un exemple (pour chaque nom de fichier coché dans un treeviexw, j'ouvre le fichier(un binaire rempli de doubles) et je fais des calculs ligne par ligne pour ajouter des points sur un MSchart :
    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
    93
    94
    95
    96
    97
                foreach (TreeNode node in treeView1.Nodes)
                {
                    foreach (TreeNode ssNode in node.Nodes)
                    {
                        if (ssNode.Checked)
                        {
                            Boolean PixelEnCours = false;
                            double DateDebutPixel = Min;
                            double DateFinPixel = DateDebutPixel + BlocTempsBase;
                            double ValeurMinPixel = 0;
                            double ValeurMaxPixel = 0;
                            double DatePixel = 0;
                            double CompteurPointsAffiches = 0;
     
                            string NomSerie = ssNode.FullPath.ToString();
     
                            // Création de la série
                            chart1.Series.Add(NomSerie); //création de la série de donnée
                            chart1.Series[NomSerie].ChartType = SeriesChartType.Range;      // série de type range pour afficher le min et le max sur la plage de temps du pixel
     
                            using (BinaryReader MonReader = new BinaryReader(File.Open(Properties.Settings.Default.CheminTravail + "\\" + ssNode.FullPath, FileMode.Open)))
                            {
                                MonReader.BaseStream.Position = 0;                          // positionnement en début de fichier et recherche dâte minimum
     
                                long FinLecture = MonReader.BaseStream.Length;  // récupération de la taille du fichier
     
                                while (MonReader.BaseStream.Position < FinLecture )
                                {
                                    double datePoint = MonReader.ReadDouble();
                                    double valeurPoint = MonReader.ReadDouble();
     
                                    if ((datePoint >= DateDebutPixel) && (datePoint < DateFinPixel)) //si le point est dans la plage de temps du pixel concerné
                                    {
                                        if (PixelEnCours == false) //c'est le premier point a afficher dans ce pixel
                                        {
                                            DatePixel = DateDebutPixel;
                                            ValeurMinPixel = valeurPoint;
                                            ValeurMaxPixel = valeurPoint;
                                            PixelEnCours = true;
                                        }
                                        else // si PixelEnCours == true, c'est au moins le deuxieme point à afficher sur ce pixel
                                        {
                                            if (valeurPoint < ValeurMinPixel) ValeurMinPixel = valeurPoint;
                                            if (valeurPoint > ValeurMaxPixel) ValeurMaxPixel = valeurPoint;
                                        }
                                    }
                                    else if ((datePoint > DateFinPixel) && (datePoint < Max)) //si on est plus dans la plage de temps du pixel concerné
                                    {
                                        if (PixelEnCours == true) // passage au pixel suivant  mais s'il y a eu des poitns dans la plage
                                        {
                                            chart1.Series[NomSerie].Points.AddXY(DatePixel, ValeurMinPixel, ValeurMaxPixel); //on charge le dernier pixel dans le graph
                                            CompteurPointsAffiches++;
                                        }
     
                                        do //recherche pixel concerné par le nouveau point
                                        {
                                            DateFinPixel += BlocTempsBase;
                                        } while (datePoint > DateFinPixel);
     
                                        DateDebutPixel = DateFinPixel - BlocTempsBase;
                                        DatePixel = DateDebutPixel;
                                        ValeurMinPixel = valeurPoint;
                                        ValeurMaxPixel = valeurPoint;
                                        PixelEnCours = true;
                                    }
                                    else
                                    {
                                        if (PixelEnCours == true) //c'est fini mais il y a un pixel en cours
                                        {
                                            chart1.Series[NomSerie].Points.AddXY(DatePixel, ValeurMinPixel, ValeurMaxPixel);
                                            CompteurPointsAffiches++;
                                            PixelEnCours = false;
                                        }
                                    }
     
                                    // Modif des markers suivant nombre de points affichés
                                    if (CompteurPointsAffiches < NbPixels / 4)
                                    {
                                        chart1.Series[NomSerie].MarkerStyle = MarkerStyle.Square;
                                        chart1.Series[NomSerie].MarkerColor = Color.Black;
                                        chart1.Series[NomSerie].ToolTip = "#VALY - #VALX{G}";
                                    }
                                    else
                                    {
                                        chart1.Series[NomSerie].ToolTip = "";
                                        chart1.Series[NomSerie].MarkerStyle = MarkerStyle.None;
                                    }
                                }
                            }
     
     
                            chart1.Series[NomSerie].IsXValueIndexed = false;                // pour avoir les absices dans l'ordre et sans trous
                            chart1.Series[NomSerie].XValueType = ChartValueType.DateTime;   // axe X de type DateTime
     
                        }
                    }
                }
    Cette boucle prend jusqu'à 5minutes aujourd'hui avec les plus gros lots de données que j'ai.
    Là, dans ce cas, on est d'accord qu'il faut que ma fonction async soit une fraction de la boucle complète pour que je puisse gérer un avancement manuellement dans la boucle qui lancera X fois la fonction async.
    Je dois même avouer que vu que le temps d’exécution n'est pas directement du aux opérations de Read dans les StreamReader, je ne vois même pas comment mettre en place le async vu que du coup je n'ai pas de méthodes async longues à gérer.

    Merci
    Il y a 10 sortes de personnes dans le monde : ceux qui comprennent le binaire et les autres

  16. #16
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par petitours Voir le message
    rien que pour en comprendre l’intérêt je ne suis pas sorti !
    Bref pas grave ca va venir...
    Eh bien c'est simple : une expression lambda devient une variable comme une autre que tu peux passer en argument à d'autres méthodes. Et c'est ça qui est très puissant en .NET. Par exemple les constructeurs statiques de Task admettent en paramètre des "Action" ou "Action<object>". Si tu fais "voir la définition" sur l'un de ces types tu verras les signatures correspondantes. Par exemple le type "Action" est la signature d'une méthode sans paramètre et qui ne renvoie rien...

    Citation Envoyé par petitours Voir le message
    Pour ce qui en est de Iprogress, si je comprends bien c'est, au même titre que l'annulation, une surcharge possible pour les méthodes Async qui sont gérée sur certaines taches très longues.
    En quelque sorte oui...

    Citation Envoyé par petitours Voir le message
    Dans mon cas j'ai l'impression que ca ne conviendrait pas parce que ce qui est long dans mon cas est
    soit le zipage évoqué tout à l'heure
    qui dure 30s mais qui ne gère pas de méthodes async :-(

    Soit des boucles très longues. en voici un exemple (pour chaque nom de fichier coché dans un treeviexw, j'ouvre le fichier(un binaire rempli de doubles) et je fais des calculs ligne par ligne pour ajouter des points sur un MSchart :
    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
    93
    94
    95
    96
    97
                foreach (TreeNode node in treeView1.Nodes)
                {
                    foreach (TreeNode ssNode in node.Nodes)
                    {
                        if (ssNode.Checked)
                        {
                            Boolean PixelEnCours = false;
                            double DateDebutPixel = Min;
                            double DateFinPixel = DateDebutPixel + BlocTempsBase;
                            double ValeurMinPixel = 0;
                            double ValeurMaxPixel = 0;
                            double DatePixel = 0;
                            double CompteurPointsAffiches = 0;
     
                            string NomSerie = ssNode.FullPath.ToString();
     
                            // Création de la série
                            chart1.Series.Add(NomSerie); //création de la série de donnée
                            chart1.Series[NomSerie].ChartType = SeriesChartType.Range;      // série de type range pour afficher le min et le max sur la plage de temps du pixel
     
                            using (BinaryReader MonReader = new BinaryReader(File.Open(Properties.Settings.Default.CheminTravail + "\\" + ssNode.FullPath, FileMode.Open)))
                            {
                                MonReader.BaseStream.Position = 0;                          // positionnement en début de fichier et recherche dâte minimum
     
                                long FinLecture = MonReader.BaseStream.Length;  // récupération de la taille du fichier
     
                                while (MonReader.BaseStream.Position < FinLecture )
                                {
                                    double datePoint = MonReader.ReadDouble();
                                    double valeurPoint = MonReader.ReadDouble();
     
                                    if ((datePoint >= DateDebutPixel) && (datePoint < DateFinPixel)) //si le point est dans la plage de temps du pixel concerné
                                    {
                                        if (PixelEnCours == false) //c'est le premier point a afficher dans ce pixel
                                        {
                                            DatePixel = DateDebutPixel;
                                            ValeurMinPixel = valeurPoint;
                                            ValeurMaxPixel = valeurPoint;
                                            PixelEnCours = true;
                                        }
                                        else // si PixelEnCours == true, c'est au moins le deuxieme point à afficher sur ce pixel
                                        {
                                            if (valeurPoint < ValeurMinPixel) ValeurMinPixel = valeurPoint;
                                            if (valeurPoint > ValeurMaxPixel) ValeurMaxPixel = valeurPoint;
                                        }
                                    }
                                    else if ((datePoint > DateFinPixel) && (datePoint < Max)) //si on est plus dans la plage de temps du pixel concerné
                                    {
                                        if (PixelEnCours == true) // passage au pixel suivant  mais s'il y a eu des poitns dans la plage
                                        {
                                            chart1.Series[NomSerie].Points.AddXY(DatePixel, ValeurMinPixel, ValeurMaxPixel); //on charge le dernier pixel dans le graph
                                            CompteurPointsAffiches++;
                                        }
     
                                        do //recherche pixel concerné par le nouveau point
                                        {
                                            DateFinPixel += BlocTempsBase;
                                        } while (datePoint > DateFinPixel);
     
                                        DateDebutPixel = DateFinPixel - BlocTempsBase;
                                        DatePixel = DateDebutPixel;
                                        ValeurMinPixel = valeurPoint;
                                        ValeurMaxPixel = valeurPoint;
                                        PixelEnCours = true;
                                    }
                                    else
                                    {
                                        if (PixelEnCours == true) //c'est fini mais il y a un pixel en cours
                                        {
                                            chart1.Series[NomSerie].Points.AddXY(DatePixel, ValeurMinPixel, ValeurMaxPixel);
                                            CompteurPointsAffiches++;
                                            PixelEnCours = false;
                                        }
                                    }
     
                                    // Modif des markers suivant nombre de points affichés
                                    if (CompteurPointsAffiches < NbPixels / 4)
                                    {
                                        chart1.Series[NomSerie].MarkerStyle = MarkerStyle.Square;
                                        chart1.Series[NomSerie].MarkerColor = Color.Black;
                                        chart1.Series[NomSerie].ToolTip = "#VALY - #VALX{G}";
                                    }
                                    else
                                    {
                                        chart1.Series[NomSerie].ToolTip = "";
                                        chart1.Series[NomSerie].MarkerStyle = MarkerStyle.None;
                                    }
                                }
                            }
     
     
                            chart1.Series[NomSerie].IsXValueIndexed = false;                // pour avoir les absices dans l'ordre et sans trous
                            chart1.Series[NomSerie].XValueType = ChartValueType.DateTime;   // axe X de type DateTime
     
                        }
                    }
                }
    Cette boucle prend jusqu'à 5minutes aujourd'hui avec les plus gros lots de données que j'ai.
    Là, dans ce cas, on est d'accord qu'il faut que ma fonction async soit une fraction de la boucle complète pour que je puisse gérer un avancement manuellement dans la boucle qui lancera X fois la fonction async.
    Je dois même avouer que vu que le temps d’exécution n'est pas directement du aux opérations de Read dans les StreamReader, je ne vois même pas comment mettre en place le async vu que du coup je n'ai pas de méthodes async longues à gérer.

    Merci
    ouhlala, ça me paraît bien compliqué ton code, déjà tu devrais pouvoir simplifier les boucles imbriquées avec Linq.

    Exemple : cette partie :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    foreach (TreeNode node in treeView1.Nodes)
    {
        foreach (TreeNode ssNode in node.Nodes)
    	{
    		if (ssNode.Checked)
    		{
    			...
    		}
    	}
    }
    peut être remplacé par :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    IEnumerable<TreeNode> ssNodes = from node in treeView1.Nodes
    			from ssNode in node.Nodes
    			where ssNode.Checked
    			select ssNode;
     
    foreach (TreeNode ssNode in ssNodes)
    {
    	...
    }
    Et rien qu'avec ça tu t'enlèves 3 niveaux d'imbrications!
    Alors dans mon exemple, je n'ai gardé que le ssNode car tu ne fais pas accès au node principal d'après ce que j'ai vu...

    Du coup, une fois cela fait, j'ai vu que tu ne fais appel qu'à "FullPath" du node. Donc ce que l'on peut faire ce serait la boucle que je t'ai montré avec à l'intérieur du "foreach" une méthode asynchrone...
    Après, le IProgress arrive là dedans pour mettre à jour tes "chars" (éléments d'IHM). Si tu regardes la doc, tu verras que la classe "Progress" s'exécute dans le contexte du thread où il a été déclaré, et c'est tout l'intérêt de cette classe.
    Il faudrait que tu arrives à regrouper dans un même bloc la mise à jour des chars pour la mettre après dans le callback de "Progress"...

    PS : tu aurais du mettre le tag "débutant" au début, sinon on ne sais pas que tu es débutant.

  17. #17
    Membre chevronné Avatar de petitours
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Février 2003
    Messages
    1 935
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2003
    Messages : 1 935
    Points : 2 013
    Points
    2 013
    Par défaut
    Citation Envoyé par Ph_Gr Voir le message
    PS : tu aurais du mettre le tag "débutant" au début, sinon on ne sais pas que tu es débutant.
    Mince je suis démasqué !
    Le soucis c'est que je ne suis pas un débutant comme les autres, je suis pire ! déformé par des années de pratique de la programmation avec des outils bien plus bas niveau d'une part et peut être plus encore par ma capacité d'abstraction, très "mécanique" qui me donne pas mal de difficultés pour m'imprégner de ces outils. Il m'a fallu plusieurs années pour piger la notion d'objet déjà !

    Par exemple là je trouve mon code avec l'imbrication de foreach bien plus lisible que la version qui va bien , écrasé par la syntaxe de IEnumerate qui introduit un truc de plus dans la boucle. Faut que je casse la carapace là !

    Je ne comprends plus rien par contre sur le coup de mettre
    Citation Envoyé par Ph_Gr Voir le message
    Donc ce que l'on peut faire ce serait la boucle que je t'ai montré avec à l'intérieur du "foreach" une méthode asynchrone...
    Le Progress n'est pas un truc en plus, une "fonctionnalité" dont dispose une méthode async ? (par exemple le readLineAsync d'un streamReader permettrait de retourner un progress alors que le ReadQqchoseAsync d'un objet machin ne disposerait pas de la surcharge permettant de gérer le Progress)

    Une fonction maison peut gérer le Progress ? genre :
    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
     
    async Task TestAsync() 
    {
    double datePoint = MonReader.ReadDouble();
                                    double valeurPoint = MonReader.ReadDouble();
     
                                    if ((datePoint >= DateDebutPixel) && (datePoint < DateFinPixel)) //si le point est dans la plage de temps du pixel concerné
                                    {
                                        if (PixelEnCours == false) //c'est le premier point a afficher dans ce pixel
                                        {
                                            DatePixel = DateDebutPixel;
                                            ValeurMinPixel = valeurPoint;
                                            ValeurMaxPixel = valeurPoint;
                                            PixelEnCours = true;
                                        }
                                        else // si PixelEnCours == true, c'est au moins le deuxieme point à afficher sur ce pixel
                                        {
                                            if (valeurPoint < ValeurMinPixel) ValeurMinPixel = valeurPoint;
                                            if (valeurPoint > ValeurMaxPixel) ValeurMaxPixel = valeurPoint;
                                        }
                                    }
                                    else if ((datePoint > DateFinPixel) && (datePoint < Max)) //si on est plus dans la plage de temps du pixel concerné
                                    {
                                        if (PixelEnCours == true) // passage au pixel suivant  mais s'il y a eu des poitns dans la plage
                                        {
                                            chart1.Series[NomSerie].Points.AddXY(DatePixel, ValeurMinPixel, ValeurMaxPixel); //on charge le dernier pixel dans le graph
                                            CompteurPointsAffiches++;
                                        }
     
                                        do //recherche pixel concerné par le nouveau point
                                        {
                                            DateFinPixel += BlocTempsBase;
                                        } while (datePoint > DateFinPixel);
     
                                        DateDebutPixel = DateFinPixel - BlocTempsBase;
                                        DatePixel = DateDebutPixel;
                                        ValeurMinPixel = valeurPoint;
                                        ValeurMaxPixel = valeurPoint;
                                        PixelEnCours = true;
                                    }
                                    else
                                    {
                                        if (PixelEnCours == true) //c'est fini mais il y a un pixel en cours
                                        {
                                            chart1.Series[NomSerie].Points.AddXY(DatePixel, ValeurMinPixel, ValeurMaxPixel);
                                            CompteurPointsAffiches++;
                                            PixelEnCours = false;
                                        }
                                    }
     
                                    // Modif des markers suivant nombre de points affichés
                                    if (CompteurPointsAffiches < NbPixels / 4)
                                    {
                                        chart1.Series[NomSerie].MarkerStyle = MarkerStyle.Square;
                                        chart1.Series[NomSerie].MarkerColor = Color.Black;
                                        chart1.Series[NomSerie].ToolTip = "#VALY - #VALX{G}";
                                    }
                                    else
                                    {
                                        chart1.Series[NomSerie].ToolTip = "";
                                        chart1.Series[NomSerie].MarkerStyle = MarkerStyle.None;
                                    }
    }
    qui ne gère aucun await parce que aucune ligne est longue en soit et parce que aucune ligne ne fait appel à une fonction async, peut intégrer du Progress ?

    Pour en revenir aux lambda et au delegate
    ceci ne m’éclaire pas
    Citation Envoyé par Ph_Gr Voir le message
    Eh bien c'est simple : une expression lambda devient une variable comme une autre que tu peux passer en argument à d'autres méthodes. Et c'est ça qui est très puissant en .NET. Par exemple les constructeurs statiques de Task admettent en paramètre des "Action" ou "Action<object>". Si tu fais "voir la définition" sur l'un de ces types tu verras les signatures correspondantes. Par exemple le type "Action" est la signature d'une méthode sans paramètre et qui ne renvoie rien...
    Parce que concrètement passer une action en paramètre je ne visualise pas du tout... Je raisonne trop "mécanique", sans doute pas très objet encore et du coup ces syntaxes introduisent à mes yeux une complexité liée à l'abstraction ajoutée alors que la seule chose qui me facilite la lecture aujourd'hui c'est la structuration de mon code, avec des fonctions bien rangées les une après les autres, dans des fichiers biens définis. Je ne pense pas comme il faut là et c'est chaud de faire autrement ! d'autant plus que les tutos et autres MSDN ne m'aident pas à piger puisque tout part de l'abstraction pour aller vers le code alors que je suis dans le cas inverse, je ne pige même pas les intros des tutos alors que je comprends la fin !

    Merci pour votre aide précieuse ! je vais passer un gros gap là une fois que ça aura percuté dans ma petite tête.


    PS : Le critère vitesse d’exécution est primordial pour moi dans le cas précis de l'exemple que j'ai donné avec le remplissage du MSchart.
    Il y a 10 sortes de personnes dans le monde : ceux qui comprennent le binaire et les autres

  18. #18
    Membre chevronné Avatar de petitours
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Février 2003
    Messages
    1 935
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2003
    Messages : 1 935
    Points : 2 013
    Points
    2 013
    Par défaut
    J'ai un peu mal aux cheveux mais j'ai progressé !!

    J'ai réussi à gérer une tache async avec une expression lambda et un report de progression
    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
            private async void button3_Click(object sender, EventArgs e)
            {
                var progressIndicator = new Progress<int>(ReportProgress); //construction de l'objet Progress<T>
     
                int EnCours = await ExampleMethodAsync(progressIndicator);
     
            }
     
            void ReportProgress(int value)
            {
                textBox1.Text =  "En cours : " + value.ToString() + " %";
            }
     
            async Task<int> ExampleMethodAsync(IProgress<int> progress)
            {
                int NombrePassages = 100;
     
                int Progression = await Task.Run<int>(async () => 
                    {
                        int EnCours = 0;
                        while (EnCours < NombrePassages)
                        {
                            await Task.Delay(300);
                            if (progress != null)
                            {
                                progress.Report(EnCours);
                            }
                            EnCours++;
                        }
                        return EnCours;
                    });
                return Progression;            
            }
    non seulement j'ai pigé ce qui se passe (à peu prés) mais c'est aussi la version "lambda" d'un code plus classique pour moi (qui fonctionne également:
    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
    private async void button3_Click(object sender, EventArgs e)
            {
                var progressIndicator = new Progress<int>(ReportProgress); //construction de l'objet Progress<T>
     
                int EnCours = await ExampleMethodAsync(progressIndicator);
     
            }
     
            void ReportProgress(int value)
            {
                textBox1.Text = "En cours : " + value.ToString() + " %";
            }
     
            async Task<int> ExampleMethodAsync(IProgress<int> progress)
            {
                int Progression = await MaFonction(progress);
     
                return Progression;
            }
     
            async Task<int> MaFonction(IProgress<int> progress)
            {
                int NombrePassages = 100;
     
                int EnCours = 0;
     
                while (EnCours < NombrePassages)
                {
                    await Task.Delay(300);
                    if (progress != null)
                    {
                        progress.Report(EnCours);
                    }
                    EnCours++;
                }
                return EnCours;
            }
    J'ai même pu me rassurer sur le fait que l'on peut faire ça y compris avec des taches qui n'utilisent pas des méthodes Async incluses dans des classes spécifiquement créées dans le Framework 4.5 (ReadLineAsync ou autres...)

    Ici mon test avec une boucle très longue bidon ne faisant appel qu'à pleins de choses très rapides
    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
            private async void button3_Click(object sender, EventArgs e)
            {
                var progressIndicator = new Progress<int>(ReportProgress); //construction de l'objet Progress<T>
     
                int EnCours = await ExampleMethodAsync(progressIndicator);
     
            }
     
            void ReportProgress(int value)
            {
                textBox1.Text = "En cours : " + value.ToString() + " %";
            }
     
            async Task<int> ExampleMethodAsync(IProgress<int> progress)
            {
                int NombreBoucle = 100 ;
                int NombrePassages = 100000000 ;
     
                int Progression = await Task.Run<int>(async () =>
                {
                    int EnCoursBoucle = 0;
                    while (EnCoursBoucle < NombreBoucle)
                    {
                      //  await Task.Delay(300);
                        if (progress != null)
                        {
                            int EnCours = 0;
                            while (EnCours < NombrePassages)
                            {
                                int temp = 0;
                                int temp1 = 0;
                                int temp2 = 0;
                                int temp3 = 0;
                                int temp4 = 0;
                                int temp5 = 0;
                                int temp6 = 0;
                                int temp7 = 0;
     
                                if (EnCours <30)temp = 34;
                                if (EnCours <40) temp1 = 44;
                                if (EnCours <450) temp2 = 44;
                                if (EnCours <4770)temp3 = 44;
                                if (EnCours <460) temp4 = 44;
                                if (EnCours <4660)temp5 = 44;
                                if (EnCours <4660)temp6 = 44;
                                if (EnCours < 46660) temp7 = 44;
     
                                int temp9 = temp + temp1 + temp2 + temp3 + temp4 + temp5 + temp6 + temp7 ;
                                EnCours++;
                            }
                            progress.Report(EnCoursBoucle);
                        }
                        EnCoursBoucle++;
                    }
                    return EnCoursBoucle;
                });
                return Progression;
            }

    Je bute maintenant sur l'annulation :

    J'en suis ici
    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
            private async void button3_Click(object sender, EventArgs e)
            {
                var progressIndicator = new Progress<int>(ReportProgress); //construction de l'objet Progress<T>
     
                cts = new CancellationTokenSource();
                try
                {
                    int EnCours = await ExampleMethodAsync(progressIndicator, cts.Token);
                }
                catch (OperationCanceledException ex)
                {
                    //Do stuff to handle cancellation
                }
     
            }
     
            void ReportProgress(int value)
            {
                textBox1.Text = "En cours : " + value.ToString() + " %";
            }
     
            async Task<int> ExampleMethodAsync(IProgress<int> progress, CancellationToken CancelToken)
            {
                int NombrePassages = 100;
     
                int Progression = await Task.Run<int>(async () =>
                {
                    int EnCours = 0;
                    while (EnCours < NombrePassages)
                    {
                        await Task.Delay(300);
     
                        CancelToken.ThrowIfCancellationRequested();
     
                        if (progress != null)
                        {
                            progress.Report(EnCours);
                        }
                        EnCours++;
                    }
                    return EnCours;
                }, CancelToken);
                return Progression;
            }
     
            private void btCancel_Click(object sender, EventArgs e)
            {
                cts.Cancel();
            }
    Mais je n'arrive pas à partager le CancellationToken entre mes différentes méthodes, comme si la surcharge correspondante n'existait pas, ça me parle de référence d'assembly qui manquerait peut être...
    Je n'arrive pas à comprendre ce qui manque.

    Pour info j'ai beaucoup avancé grâce à ce lien
    http://blogs.msdn.com/b/dotnet/archi...sync-apis.aspx

    Merci pour le coup de pousse, c'est rude mais très motivant !
    Il y a 10 sortes de personnes dans le monde : ceux qui comprennent le binaire et les autres

  19. #19
    Membre chevronné Avatar de petitours
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Février 2003
    Messages
    1 935
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2003
    Messages : 1 935
    Points : 2 013
    Points
    2 013
    Par défaut
    j'ai fini par trouver ce qui manquait pour l'annulation
    j'ai ceci qui s’exécute bien maintenant
    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
            CancellationTokenSource cts;
     
            private async void button3_Click(object sender, EventArgs e)
            {
                var progressIndicator = new Progress<int>(ReportProgress); //construction de l'objet Progress<T>
     
                cts = new CancellationTokenSource();
                try
                {
                    int EnCours = await ExampleMethodAsync(progressIndicator, cts.Token);
                }
                catch (OperationCanceledException)
                {
                    textBox1.Text = "Test annulé !";
                }
                catch (Exception)
                {
                    textBox1.Text = "Erreur sur test !";
                }
     
            }
     
            void ReportProgress(int value)
            {
                textBox1.Text = "En cours : " + value.ToString() + " %";
            }
     
            async Task<int> ExampleMethodAsync(IProgress<int> progress, CancellationToken CancelToken)
            {
                int NombrePassages = 100;
     
                int Progression = await Task.Run<int>(async () =>
                {
                    int EnCours = 0;
                    while (EnCours < NombrePassages)
                    {
                        await Task.Delay(100);
     
                        CancelToken.ThrowIfCancellationRequested();
     
                        if (progress != null)
                        {
                            progress.Report(EnCours);
                        }
                        EnCours++;
                    }
                    return EnCours;
                }, CancelToken);
                return Progression;
            }
     
            private void btCancel_Click(object sender, EventArgs e)
            {
                cts.Cancel();
            }
    Le soucis c'est que ça annule rien du tout...
    Il y a 10 sortes de personnes dans le monde : ceux qui comprennent le binaire et les autres

  20. #20
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par petitours Voir le message
    Le soucis c'est que ça annule rien du tout...
    Bonjour,

    Je viens de tester ton code et l'annulation fonctionne impeccablement... J'ai bien eu le message "Test annulé !" quand j'ai cliqué sur le bouton "Cancel". Pourquoi dis-tu que ça n'annule rien du tout?

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 3 123 DernièreDernière

Discussions similaires

  1. Remplir Treeview depuis DataTable
    Par Anaxagore dans le forum Windows Forms
    Réponses: 10
    Dernier message: 19/03/2009, 22h44
  2. remplissage tableau depuis une jsp
    Par naetoila dans le forum Servlets/JSP
    Réponses: 1
    Dernier message: 02/12/2008, 11h16
  3. remplissage treeview dynamique
    Par bingo00 dans le forum C#
    Réponses: 4
    Dernier message: 20/05/2007, 23h13
  4. [C#] Remplir treeview depuis string[] de paths
    Par joujoukinder dans le forum Windows Forms
    Réponses: 4
    Dernier message: 15/12/2006, 11h06
  5. 'erreur 35601' lors du remplissage treeview
    Par GAGNON dans le forum Access
    Réponses: 18
    Dernier message: 30/11/2006, 19h51

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