Menu

C#, attendre

MOI - 3 juin 2018 à 11:03 - Dernière réponse : Reivax962 3238 Messages postés jeudi 16 juin 2005Date d'inscription 22 juin 2018 Dernière intervention
- 22 juin 2018 à 13:45
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

Afficher la suite 

Votre réponse

30 réponses

Whismeril 11635 Messages postés mardi 11 mars 2003Date d'inscriptionContributeurStatut 22 juin 2018 Dernière intervention - 3 juin 2018 à 13:38
0
Merci
Bonjour,
il faut que tu utilises un thread séparé.
Le backgroundworker me parrait adapté.
Commenter la réponse de Whismeril
0
Merci
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...
Commenter la réponse de MOI
Whismeril 11635 Messages postés mardi 11 mars 2003Date d'inscriptionContributeurStatut 22 juin 2018 Dernière intervention - 4 juin 2018 à 12:25
0
Merci
Ton objet chrome ne te signale pas quand c’est chargé, avec une propriété ou un événement?
Commenter la réponse de Whismeril
Whismeril 11635 Messages postés mardi 11 mars 2003Date d'inscriptionContributeurStatut 22 juin 2018 Dernière intervention - 4 juin 2018 à 22:47
0
Merci
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.

Commenter la réponse de Whismeril
0
Merci
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.
Reivax962 3238 Messages postés jeudi 16 juin 2005Date d'inscription 22 juin 2018 Dernière intervention - 5 juin 2018 à 10:35
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
Commenter la réponse de MOI
Whismeril 11635 Messages postés mardi 11 mars 2003Date d'inscriptionContributeurStatut 22 juin 2018 Dernière intervention - 5 juin 2018 à 12:21
0
Merci
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
http://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.
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).
Whismeril 11635 Messages postés mardi 11 mars 2003Date d'inscriptionContributeurStatut 22 juin 2018 Dernière intervention - 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.
Commenter la réponse de Whismeril
0
Merci
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
Whismeril 11635 Messages postés mardi 11 mars 2003Date d'inscriptionContributeurStatut 22 juin 2018 Dernière intervention > Reivax962 3238 Messages postés jeudi 16 juin 2005Date d'inscription 22 juin 2018 Dernière intervention - 11 juin 2018 à 17:27
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à.
Reivax962 3238 Messages postés jeudi 16 juin 2005Date d'inscription 22 juin 2018 Dernière intervention - 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.
Whismeril 11635 Messages postés mardi 11 mars 2003Date d'inscriptionContributeurStatut 22 juin 2018 Dernière intervention - 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.
Reivax962 3238 Messages postés jeudi 16 juin 2005Date d'inscription 22 juin 2018 Dernière intervention - 12 juin 2018 à 11:31
Je m'incline devant toutes ces recherches, je n'en ai pas fait autant ^^
Whismeril 11635 Messages postés mardi 11 mars 2003Date d'inscriptionContributeurStatut 22 juin 2018 Dernière intervention > Reivax962 3238 Messages postés jeudi 16 juin 2005Date d'inscription 22 juin 2018 Dernière intervention - 12 juin 2018 à 16:23
en tout cas, je te conseille les tutos de fdorin, je pense que le pool de thread simplifie pas mal de chose.
Commenter la réponse de Moi
Whismeril 11635 Messages postés mardi 11 mars 2003Date d'inscriptionContributeurStatut 22 juin 2018 Dernière intervention - 11 juin 2018 à 17:58
0
Merci
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://msdn.microsoft.com/fr-fr/library/system.data.dataset(v=vs.110).aspx 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.
Commenter la réponse de Whismeril
0
Merci
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.
Commenter la réponse de Moi
0
Merci
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
Commenter la réponse de Moi
Whismeril 11635 Messages postés mardi 11 mars 2003Date d'inscriptionContributeurStatut 22 juin 2018 Dernière intervention - 18 juin 2018 à 19:18
0
Merci
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://www.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.

Commenter la réponse de Whismeril
0
Merci
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
Whismeril 11635 Messages postés mardi 11 mars 2003Date d'inscriptionContributeurStatut 22 juin 2018 Dernière intervention - 19 juin 2018 à 06:51
Et as tu essayé la syntaxe de Xavier?
Commenter la réponse de Moi
0
Merci
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" !
Reivax962 3238 Messages postés jeudi 16 juin 2005Date d'inscription 22 juin 2018 Dernière intervention - 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
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.. :-/
Reivax962 3238 Messages postés jeudi 16 juin 2005Date d'inscription 22 juin 2018 Dernière intervention - 22 juin 2018 à 11:40
S'il y a bien le code source dans la variable source, c'est que le await a fonctionné...
Ha non je t'assure, le await est quasi instanné, mais l'affichage ne l'est pas.
J'ai moyen de vérifier si je suis sur la bonne page avec mon traitement sur le code source, et je ne le suis jamais.
Reivax962 3238 Messages postés jeudi 16 juin 2005Date d'inscription 22 juin 2018 Dernière intervention - 22 juin 2018 à 13:45
> Ha non je t'assure, le await est quasi instanné, mais l'affichage ne l'est pas.
Oui mais tu as bien le code source. L'affichage peut mettre du temps pour d'autres raisons : s'il y a des javascripts, s'il y a des images, s'il y a des redirections...
Ta fonction GetSource ne fait probablement aucune exécution de javascript et ne charge pas les images.
Je te suggère d'ouvrir ta page dans le navigateur en activant les outils d'analyse réseau pour vérifier tous les appels qui sont faits, et voir si tu ne peux pas remplacer l'url que tu appelles dans ton code par une url mieux ciblées.
Commenter la réponse de Moi