C#, attendre

Fermé
MOI - 3 juin 2018 à 11:03
Reivax962 Messages postés 3671 Date d'inscription jeudi 16 juin 2005 Statut Membre Dernière intervention 11 février 2021 - 25 juin 2018 à 11:28
Bonjour,

Dans mon application Windows en C# j'ai mis un contrôle Chrome/Chronium
Je charge une page Internet via un simple Button, et je souhaiterai attendre que le chargement soit complet avant de continuer la suite du code.
Si je fais "System.Threading.Thread.Sleep(10000);" cela bloque le chargement et toute l'application.
Est-ce qu'il y a moyen de laisser l'application tourner tout en mettant le code en pause... Si vous voyez ce que je veux dire ?

D'avance merci

13 réponses

Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 929
3 juin 2018 à 13:38
Bonjour,
il faut que tu utilises un thread séparé.
Le backgroundworker me parrait adapté.
0
Merci pour la réponse mais du coup je comprends pas.
Quand je fais appelle à backgroundworker .RunWorkerAsync, il faut que je passe quoi en paramètre ? J'ai essayé avec chrome, c'est à dire l'objet mais il se n'aime pas le paramètre. Si j'essaie de passer le "Sleep", c'est pareil. Du coup je pige pas trop comment m'en servir.

Le but de mon application est simple, attendre 10 secondes que le page soit chargée pour ensuite récupérer le code source.

chrome.Load("https://www.monsite.fr");
Task<String> SourceHTML = chrome.GetSourceAsync();
TxtSource.Text = SourceHTML.Result;

Le fait de faire un sleep bloque le chargement de la page...
0
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 929
4 juin 2018 à 12:25
Ton objet chrome ne te signale pas quand c’est chargé, avec une propriété ou un événement?
0
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 929
4 juin 2018 à 22:47
A priori ceci répond à ce que tu veux.
https://stackoverflow.com/questions/41985380/cefsharp-documentcompleted

Là ou le gard a marqué
// Page has finished loading, do whatever you want here


C'est là qu'il faut lire le code de ta page.

0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Ca marche pas non plus. J'avais trouvé ce code
(ou alors je m'y prend mal, désolé je débute)...
En fait mon code est le suivant :

private void BtnGo_Click(object sender, EventArgs e)
{
            this.Cursor = Cursors.WaitCursor;
            Parcours = true;

            foreach (DataRow Rec in DataSet.Rec.Rows) 
            {
                     chrome.Load ("https://www.monsite" + Rec[0]);
                     //Task<String> SourceHTML = chrome.GetSourceAsync();
                     //TxtSource.Text = SourceHTML.Result;

                     // TRAITEMENT VIS A VIS DU SOURCE...... 
            }

            this.Cursor = Cursors.Default;
        }

        private void OnLoadingStateChanged(object sender, LoadingStateChangedEventArgs args)
        {

            if ((!args.IsLoading) && (Parcours))
            {
                Task<String> SourceHTML = chrome.GetSourceAsync();
                TxtSource.Text = SourceHTML.Result;
            }
        }



Le truc c'est que ma boucle foreach n'attend pas que la page soit chargée et donc ça passe d'une page à l'autre sans que j'ai le temps de récupérer ce que je veux vraiment.
En faisant un Sleep, le chargement se bloque.

Je ne sais pas si je suis vraiment très clair dans ce que je veux faire.

EDIT : Ajout des balises de code (la coloration syntaxique).
Explications disponibles ici : ICI

Merci d'y penser dans tes prochains messages.
0
Reivax962 Messages postés 3671 Date d'inscription jeudi 16 juin 2005 Statut Membre Dernière intervention 11 février 2021 1 011
Modifié le 5 juin 2018 à 10:36
Bonjour,

Je ne connais pas les API chrome, mais tu dois pouvoir utiliser await.
Plutôt que ça :
//Task<String> SourceHTML = chrome.GetSourceAsync();
//TxtSource.Text = SourceHTML.Result;

Essaie ceci :
var source = await chrome.GetSourceAsync();


Du coup la fonction doit être déclarée async :
private async void BtnGo_Click


Xavier
0
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 929
5 juin 2018 à 12:21
Maintenant qu’Edouard a rendu ton code lisible, on peut parler.
La prochaine fois, merci de mettre en forme, voir l'encadré bleu ajouté par Edouard.

Tu n’avais pas parlé de boucle jusque là donc je ne peux pas en avoir tenu compte.
Oui Thread.Sleep ça bloque tout le thread, c’est à ça que ça sert et c’est une pratique à éviter.

Tu débutes, ok c’est pas grave, on a tous débuté.
Mais j’ai l’impression que comme beaucoup (moi y compris à une autre époque) tu crois que tu peux battre le record du 100m sans avoir pris la peine d’apprendre à marcher.
Je te conseille de pendre quelques jours à apprendre les bases, ce cours est bien
https://tahe.developpez.com/dotnet/csharp/
Et de revenir sur ton projet ensuite.

Revenons à ta question.
Si je comprends bien, tu as une collection de pages que tu veux charger, les une après les autres.
Et ensuite tu veux afficher le code source de ces pages dans un controle.
En l’état, même si on traite la synchronisation du chargement, le nouveau code de page n va remplacer celui de la page n-1.

Explique ton besoin, et pas la solution que tu penses appliquer.
0
Désolé je n'ai aucune envie de battre le record du 100 m, ça m'intéresse pas, mon seul et unique soucis c'est le temps d'attente pour charger une page Web pour pouvoir ensuite récupérer le code Source. Rien de plus, pas de 100 m, de JO ou de coupe du monde.
Si je pensais que le fait de faire une boucle ou pas changeait quelque chose je l'aurais précisé, mais je comprends pas en quoi ça change quelque chose, mais soit.

Tout est dans le code qu'Edouard à remis en place

-Je fais une boucle
-Je charge une page
-Je souhaite patienter que cette page soit chargée
- Je fais un traitement sur le code source que j'ai récupéré (ça y'a aucun problème).
0
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 929
9 juin 2018 à 13:43
Si je pensais que le fait de faire une boucle ou pas changeait quelque chose je l'aurais précisé, mais je comprends pas en quoi ça change quelque chose


En supposant que le chargement de la page soit instantané (c'est pas la cas, c'est pour juste expliquer)

Pour chaque URL dans la liste
  • charger l'url => 1 ms
  • mettre le code source dans (un textbox, un richText, autre?) 1ms

Fin pour Chaque => 1ms

Les codes sources vont s'afficher les uns à la place des autres, et à la fin de l'itération dans le contrôle il n'y aura que la dernière page.

En prenant en compte le temps de chargement, tu auras quelques secondes par page pour voir le code source.
Si ce que tu cherches est de les faire défiler sans avoir le temps de rien en faire, alors OK.
Si par contre, tu souhaites pouvoir lire, copier, coller, modifier etc alors c'est pas bon.

D'ou ma question sur le besoin et non la solution.
0
Comme préciser juste avant, j'ai effectivement besoin de récupérer le code source pour l'analyser et y récupérer des données
0
Reivax962 Messages postés 3671 Date d'inscription jeudi 16 juin 2005 Statut Membre Dernière intervention 11 février 2021 1 011
Modifié le 11 juin 2018 à 14:06
Bonjour,

Tu as essayé ce que je t'ai suggéré ? (là : https://forums.commentcamarche.net/forum/affich-35397482-c-attendre#6)

Xavier
0
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 929 > Reivax962 Messages postés 3671 Date d'inscription jeudi 16 juin 2005 Statut Membre Dernière intervention 11 février 2021
Modifié le 11 juin 2018 à 17:28
Bonsoir Xavier,

il a utilisé la syntaxe du pool de thread, ça revient plus ou moins au même que la tienne, mais sait on jamais.

Mais je ne pense pas que le problème se situe là.
0
Reivax962 Messages postés 3671 Date d'inscription jeudi 16 juin 2005 Statut Membre Dernière intervention 11 février 2021 1 011
12 juin 2018 à 08:25
Tu es sûr ?
Moi quand je vois ça :
                Task<String> SourceHTML = chrome.GetSourceAsync();
TxtSource.Text = SourceHTML.Result;

Je ne vois aucune attente entre l'appel à un code Async et la récupération de son résultat.
0
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 929
12 juin 2018 à 10:26
Sûr de rien surtout.... Je me base sur cette suite de tutos
https://fdorin.developpez.com/tutoriels/csharp/threadpool/part1/
que j’ai lue avec intérêt mais que je n’ai pas encore appliqué.
Et aussi parce qu’on retrouve cette syntaxe dans quelques posts sur stackoverflow.

D’un autre côté, puisque la page est chargée, je ne vois pas trop l’intérêt de récupérer son code de manière asynchrone.
Peut-être que l’api chrome ne travaille propose pas de méthode synchrone.
0
Reivax962 Messages postés 3671 Date d'inscription jeudi 16 juin 2005 Statut Membre Dernière intervention 11 février 2021 1 011
12 juin 2018 à 11:31
Je m'incline devant toutes ces recherches, je n'en ai pas fait autant ^^
0
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 929
11 juin 2018 à 17:58
Désolé je n'ai aucune envie de battre le record du 100 m, ça m'intéresse pas, mon seul et unique soucis c'est le temps d'attente pour charger une page Web pour pouvoir ensuite récupérer le code Source. Rien de plus, pas de 100 m, de JO ou de coupe du monde.


Oui mais le truc, c'est qu'utiliser des thread d'un point de vue programmation ça équivaut à déjà être athlète. Si cette image ne te parle pas en voilà une plus mathématique.
Tu veux résoudre une équation différentielle avant d'avoir appris l'addition.


Mais soit, essayons.

Procédons par étape, la première étant de faire en sorte qu'une page s'affiche.

Il faut vérifier que cette ligne existe bien dans ton code, et qu'elle est exécutée une fois et une seule, bien en amont du chargement de la première page (dans le load du formulaire par exemple)
 chrome.LoadingStateChanged += OnLoadingStateChanged;

Tu peux placer un point d'arrêt pour vérifier l'exécution et qu'elle est bien unique.


Tu as utilisé cette syntaxe
DataSet.Rec.Rows
, dans l'aide en ligne du DataSet https://docs.microsoft.com/fr-fr/dotnet/api/system.data.dataset?redirectedfrom=MSDN&view=netframework-4.8 je ne trouve pas la propriété Rec

Es tu sûr que c'est correct?
Perso, je ne me sers jamais de DataSet, donc je me reporte à la doc et la doc ne colle pas.
Donc cette partie est à vérifier.


En attendant, à la place de ton foreach on va essayer ça
                     chrome.Load ("https://www.commentcamarche.net/");


Et ensuite, mettre un point d'arrêt sur le if de
        private void OnLoadingStateChanged(object sender, LoadingStateChangedEventArgs args)
        {

            if ((!args.IsLoading) && (Parcours))
            {
                Task<String> SourceHTML = chrome.GetSourceAsync();
                TxtSource.Text = SourceHTML.Result;
            }
        }


Pour vérifier
  • que ce code est exécuté (éventuellement plusieurs fois)
  • qu'une fois la page chargée, args.IsLoading vaut false
  • que Parcours vaut true


Une fois tout ça vérifié, il faut exécuter en pas à pas pour voir si ces 2 lignes
            {
                Task<String> SourceHTML = chrome.GetSourceAsync();
                TxtSource.Text = SourceHTML.Result;
            }

Et si le code source est bien écrit dans TxtSource.

PS, je n'essayerais pas chez moi Google est banni de ma machine.
0
Merci pour ta réponse.
Alors OK je veux être un athlète, le truc c'est que je pensais pas qu'aucune personne au monde n'était un athlète avant moi. Ca je pouvais pas le savoir. Je pensais pas être la première personne au monde à faire ce que je voulais faire. Je pensais pouvoir trouver des entraîneurs ou des trucs comme ça mais non, personne.

Pour le code que tu m'as écris, il passe une seule fois dans l’événement mais n'affiche pas le code source dans le textbox. D'ailleurs en faisant comme ça, cela bloque Chronium, je peux plus naviguer avec.

J'ai essayé en mettant un timer qui toutes les 10 secondes appelle une autre fonction (3 fonctions au total)
au bout de 15 secondes : aller sur la page suivante
au bout de 15 secondes : charger le code source
au bout de 15 secondes : analyser le code source
Mais non, toujours ce problème de Thread à la con !

je tiens à précise que j'utilise Chronium car avec le composant Webbrowser, la page s'affiche pas correctement (plein d'erreurs javascripts dans tous les sens)

Concernant le Dataset , la propriété "Rec" est le nom de ma table, ceci n'est vraiment pas un soucis.

Je récapitule mon besoin :

(Boucle de parcours des enregistrements d'une table) // Aucun problème
{
Chargement d'une page dans Chrome en fonction d'une colonne de ma table // Aucun problème
Attente du chargement de la page pour récuperer le code source // Problème
Récupération du code source
Analyse du code source // Aucun problème
Mise à jour de ma base de données avec les informations récupérées // Aucun problème
}

Je suis prêt à faire cela autrement, j'ai commencé comme ça en pensant que plein de gens l'auraient fait avant moi et que je trouverais des tutos sur Internet mais je suis ouvert à faire d'une total autre manière si vous avez des idées.
0
Il y a quelques années j'avais fait la même chose en VB :

    Set rs = Base.OpenRecordset("SELECT * FROM Tournoi2 WHERE Avancement <> 'FI'")
    If rs.RecordCount > 0 Then
        rs.MoveFirst
        
        While Not rs.EOF
            WebScore.navigate "http://www.monsite" & rs(0)"
                       
            varTimer = Timer
            While varTimer + 10 > Timer
                DoEvents
            Wend
                            
        ' Récupération de la source
            Set objDocument = objMSHTML.createDocumentFromUrl("http://www.monsite=" & rs(0))
            While objDocument.readyState <> "complete"
                DoEvents
            Wend
            
            SourceFiche = objDocument.documentElement.outerHTML
             ' Traitement du source.....
             [...]
            ' Mise à jours base ...
             [...]

            rs.Next
        Wend    
 End if
0
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 929
18 juin 2018 à 19:18
Et ben, silence pendant 1 semaine et là pleins d'infos d'un coup.

Concernant le Dataset , la propriété "Rec" est le nom de ma table, ceci n'est vraiment pas un soucis.

OK

Il y a quelques années j'avais fait la même chose en VB :

Si tu avais commencé par dire que tu as codé en VB avant, je n'aurais pas cru que
désolé je débute
veut dire c'est la première fois que je code de ma vie.

Même si la philosophie de C# est fortement différente de VB6, y'a quand même des socles communs.

De ce "vieux" code, tu as utilisé des DoEvents, te souviens tu pourquoi?
Et bien pour dire aux autres threads du programme, et même à windows, "je flane, faites vos trucs de votre coté, moi je m'y remets plus tard". Et tu n'as pas mis, à l'époque, de Sleep, qui voulait déjà dire, "on stoppe tout".

Comme C# est tout objet, normalement, l'équivalent de DoEvents n'est pas utile.
Tout objet bien conçu, se doit d'avertir son environnement quand il a finit son travail, par un événement dans la très grande majorité des cas.
En VB6, la grande majorité des codeurs n'utilisait que les évènement des éléments graphiques.

S'abonner à un évènement évite d'écrire une boucle avec un DoEvents, mais derrière c'est un peu la même chose, y'a un "aiguilleur" qui scrute les messages et qui réveille la méthode qui va bien quand le message est pour elle.

Là l'idée serait
  • Charger une page
    • Quand l'événement est émis, lire le code source
    • Quand le code source est lu, charger la page suivante.


C'est que fait ton code VB6, il attend bien que la page soit chargée et lue avant de passer à la suivante.
Mais c'est pas ce que ton code C# fait, il passe tout de suite à la suivante.
Pour attendre le bon moment, je suggère d'utiliser les bons évènements, on ne se servirait alors pas de boucle.
Mais avant d'en arriver là, on va essayer d'en charger une.

Revenons donc à
Pour le code que tu m'as écris, il passe une seule fois dans l’événement mais n'affiche pas le code source dans le textbox. D'ailleurs en faisant comme ça, cela bloque Chronium, je peux plus naviguer avec.

Est ce que ça veut dire que ça passe dans le if?
Est ce que les 2 lignes sont bien exécutées? Visual Studio, a parfois la mauvaise manie de ne pas exécuter une ligne sans pour autant signaler d'erreur.... d'où ma demande de le faire en pas à pas.
Si la ligne en surbrillance atteint } c'est exécuté, si ça saute directement ailleurs dans le code, ça n'est pas exécuté.

Si oui, as tu essayé la syntaxe proposée par Xavier ici https://forums.commentcamarche.net/forum/affich-35397482-c-attendre#6 ?

Si oui aussi, peux tu donner un lien vers la doc de ton objet chromium, parce que j'en trouve plusieurs, qui ont des syntaxes proches et du coup, je ne suis pas certain de ce que je peux te proposer.
Si par exemple, il y avait un mode de lecture synchrone, on pourrait au moins comparer les comportements.

0
Alors en fait quand je fais les 2 lignes, il ne passe jamais sur le }, il est bloqué sur la ligne et plus rien ne se passse. Il ne me rend pas la main ensuite d'ailleurs :

TxtSource.Text = SourceHTML.Result;


Concernant la doc Chronium que j'ai utilisé, il s'agit de ce tuto :
https://www.youtube.com/watch?v=qSAkPUALEkA
0
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 929
19 juin 2018 à 06:51
Et as tu essayé la syntaxe de Xavier?
0
Oui j'avais essayé et ça change rien il passe sur la ligne, sans que ça change quoi que ce soit. Il ne fait pas de "wait" !
0
Reivax962 Messages postés 3671 Date d'inscription jeudi 16 juin 2005 Statut Membre Dernière intervention 11 février 2021 1 011
22 juin 2018 à 09:09
Et "source" reste vide ?
0
Non il n'est pas vide, il y a le source de la page d'accueil.
En fait là j'ai fait un test avec une boucle devant parcourir 27 pages. Les 27 sources sont identiques car c'est beaucoup trop rapide et c'est toujours le source de la page initiale qui est chargée !

Je me suis repenché sur le backgroundworker mais je n'arrive pas à le faire marcher.
Est-il possible de faire un backgroundworker d'un sleep pendant 10 secondes ?
0
Reivax962 Messages postés 3671 Date d'inscription jeudi 16 juin 2005 Statut Membre Dernière intervention 11 février 2021 1 011
Modifié le 22 juin 2018 à 10:59
Ah, mais du coup ton problème est tout autre... Tu arrives bien à récupérer les sources, mais c'est ton appel aux différentes pages qui ne doit pas être bon.

Concentrons-nous sur cette boucle :
 foreach (DataRow Rec in DataSet.Rec.Rows) 
{
       var url = "https://www.monsite" + Rec[0];
       chrome.Load (url);
       var source = await chrome.GetSourceAsync();

      // TRAITEMENT VIS A VIS DU SOURCE...... 
}

Est-ce que tu es sûr qu'à chaque itération de la boucle, l'URL donnée
"https://www.monsite" + Rec[0]
te donne bien la page qui t'intéresse ? Mets un point d'arrêt, et copie-colle la valeur de "url" dans ton navigateur pour le vérifier.
Ensuite, tu veux faire quoi avec ce code source, à chaque itération de ta boucle ?

Xavier
0
Oui oui mes URL sont bonnes, y'a pas de soucis.

Le but comme précisé avant, c'est de récupérer certaine valeur dans le code source. C'est juste du traitement sur des chaînes de caractères, ça y'a pas de problème.
Mon unique problème est d'attendre que la page soit bien chargée en fait. Le await ne marche pas.. :-/
0
Reivax962 Messages postés 3671 Date d'inscription jeudi 16 juin 2005 Statut Membre Dernière intervention 11 février 2021 1 011
22 juin 2018 à 11:40
S'il y a bien le code source dans la variable source, c'est que le await a fonctionné...
0