Salut,
On Thu, 6 Jan 2005 16:09:01 +0100, AlexC wrote:J'ai trouvé, mais je ne comprends pas pourquoi ...
Il suffit d'enlever le Thread "DebutThreadAttente"
et de remplacer dans le gestionnaire d'évènemement du timer le
Thread.start
par
frm_wait.show et ca marche ...
Dans ta methode précédente, tu lancait un thread qui se contentait
d'afficher ta fenetre d'attente de maniere non modale (Show ne bloque
pas).
Donc ton thread affichait ta fenetre puis terminait (vu qu'il n'avait plus
rien a faire) entrainant du coup la destruction de ta fenetre. La solution
aurait été d'appeler ShowDialog (bloquante tant que la fenetre n'a pas été
fermée) au lieu de Show. Mais de toute facon, cette solution d'utilier un
autre thread pour afficher ta fenetre était tres crade et t'aurai apporté
tout un tas de bugs bizarres.
Dans ta nouvelle methode, j'imagine que utilise le timer de l'espace de
nom
Windows.Form. Lorsque que ce timer "tick", ta fonction TimerWait_Tick est
executée dans le thread principal (d'ou le timer a été lancé) et non pas
dans un nouveau thread (c'est la particularité du timer Windows.From
comparé aux autres timers disponibles en .NET). Ce thread principal a 2
particularités:
- il ne termine que lorsque tu fermes ton appli
- il possede un boucle de message (c'est cette boucle qui permet aux
fenetres de rester affichées et de recevoir les evenements - ou messages -
clavier, souris...)
Donc ta fonction TimerWait_Tick affiche ta fenetre d'attente dans le
thread
principal puis se termine. Seulement le thread dans lequel est affichée ta
fenetre est toujours la lui, ta fenetre n'est donc pas détruite et reste
affichée.
Cela dit, cela m'étonne quand meme que ta fenetre soit affichée. Car
lorsque TimerWait_Tick s'exécute, ton thread principal devrait en théorie
etre bloqué par l'appel synchrone au service Web et donc incapable de
faire
quoique ce soit, y compris d'afficher ta fenetre (qui ne serait du coup
affichée qu'a la fin de l'appel au service web). Donc je pense que lors de
tes tests, le timer a tické avant que l'appel au web service n'ai
réellement commencé ou alors lorsqu'il était déja terminé. Ce qui n'est
pas
ce que tu cherche a faire je pense.
Dans tout les cas, ton approche ne me semble pas etre la bonne. La regle
d'or pour les applis Windows (c'est dans la doc): tout ce qui a trait a
l'UI doit se faire dans un et un seul thread (le thread principal). Sinon,
bugs bizarres quasiment certains (d'ou mon commentaire sur ta premiere
solution). De plus, toute opération longue et bloquante doit etre évitée
dans le thread principal (celui de l'UI) afin d'éviter que ton appli ne
soit gelée. Donc la solution est: lance l'appel a ton web service de
maniere asychrone en passant l'adresse d'une fonction callback a appeler
lorsque l'appel sera terminé; puis démarre ton Timer; puis dans ta
fonction
callback ferme la fenetre d'attente si elle a été affichée.
Salut,
On Thu, 6 Jan 2005 16:09:01 +0100, AlexC wrote:
J'ai trouvé, mais je ne comprends pas pourquoi ...
Il suffit d'enlever le Thread "DebutThreadAttente"
et de remplacer dans le gestionnaire d'évènemement du timer le
Thread.start
par
frm_wait.show et ca marche ...
Dans ta methode précédente, tu lancait un thread qui se contentait
d'afficher ta fenetre d'attente de maniere non modale (Show ne bloque
pas).
Donc ton thread affichait ta fenetre puis terminait (vu qu'il n'avait plus
rien a faire) entrainant du coup la destruction de ta fenetre. La solution
aurait été d'appeler ShowDialog (bloquante tant que la fenetre n'a pas été
fermée) au lieu de Show. Mais de toute facon, cette solution d'utilier un
autre thread pour afficher ta fenetre était tres crade et t'aurai apporté
tout un tas de bugs bizarres.
Dans ta nouvelle methode, j'imagine que utilise le timer de l'espace de
nom
Windows.Form. Lorsque que ce timer "tick", ta fonction TimerWait_Tick est
executée dans le thread principal (d'ou le timer a été lancé) et non pas
dans un nouveau thread (c'est la particularité du timer Windows.From
comparé aux autres timers disponibles en .NET). Ce thread principal a 2
particularités:
- il ne termine que lorsque tu fermes ton appli
- il possede un boucle de message (c'est cette boucle qui permet aux
fenetres de rester affichées et de recevoir les evenements - ou messages -
clavier, souris...)
Donc ta fonction TimerWait_Tick affiche ta fenetre d'attente dans le
thread
principal puis se termine. Seulement le thread dans lequel est affichée ta
fenetre est toujours la lui, ta fenetre n'est donc pas détruite et reste
affichée.
Cela dit, cela m'étonne quand meme que ta fenetre soit affichée. Car
lorsque TimerWait_Tick s'exécute, ton thread principal devrait en théorie
etre bloqué par l'appel synchrone au service Web et donc incapable de
faire
quoique ce soit, y compris d'afficher ta fenetre (qui ne serait du coup
affichée qu'a la fin de l'appel au service web). Donc je pense que lors de
tes tests, le timer a tické avant que l'appel au web service n'ai
réellement commencé ou alors lorsqu'il était déja terminé. Ce qui n'est
pas
ce que tu cherche a faire je pense.
Dans tout les cas, ton approche ne me semble pas etre la bonne. La regle
d'or pour les applis Windows (c'est dans la doc): tout ce qui a trait a
l'UI doit se faire dans un et un seul thread (le thread principal). Sinon,
bugs bizarres quasiment certains (d'ou mon commentaire sur ta premiere
solution). De plus, toute opération longue et bloquante doit etre évitée
dans le thread principal (celui de l'UI) afin d'éviter que ton appli ne
soit gelée. Donc la solution est: lance l'appel a ton web service de
maniere asychrone en passant l'adresse d'une fonction callback a appeler
lorsque l'appel sera terminé; puis démarre ton Timer; puis dans ta
fonction
callback ferme la fenetre d'attente si elle a été affichée.
Salut,
On Thu, 6 Jan 2005 16:09:01 +0100, AlexC wrote:J'ai trouvé, mais je ne comprends pas pourquoi ...
Il suffit d'enlever le Thread "DebutThreadAttente"
et de remplacer dans le gestionnaire d'évènemement du timer le
Thread.start
par
frm_wait.show et ca marche ...
Dans ta methode précédente, tu lancait un thread qui se contentait
d'afficher ta fenetre d'attente de maniere non modale (Show ne bloque
pas).
Donc ton thread affichait ta fenetre puis terminait (vu qu'il n'avait plus
rien a faire) entrainant du coup la destruction de ta fenetre. La solution
aurait été d'appeler ShowDialog (bloquante tant que la fenetre n'a pas été
fermée) au lieu de Show. Mais de toute facon, cette solution d'utilier un
autre thread pour afficher ta fenetre était tres crade et t'aurai apporté
tout un tas de bugs bizarres.
Dans ta nouvelle methode, j'imagine que utilise le timer de l'espace de
nom
Windows.Form. Lorsque que ce timer "tick", ta fonction TimerWait_Tick est
executée dans le thread principal (d'ou le timer a été lancé) et non pas
dans un nouveau thread (c'est la particularité du timer Windows.From
comparé aux autres timers disponibles en .NET). Ce thread principal a 2
particularités:
- il ne termine que lorsque tu fermes ton appli
- il possede un boucle de message (c'est cette boucle qui permet aux
fenetres de rester affichées et de recevoir les evenements - ou messages -
clavier, souris...)
Donc ta fonction TimerWait_Tick affiche ta fenetre d'attente dans le
thread
principal puis se termine. Seulement le thread dans lequel est affichée ta
fenetre est toujours la lui, ta fenetre n'est donc pas détruite et reste
affichée.
Cela dit, cela m'étonne quand meme que ta fenetre soit affichée. Car
lorsque TimerWait_Tick s'exécute, ton thread principal devrait en théorie
etre bloqué par l'appel synchrone au service Web et donc incapable de
faire
quoique ce soit, y compris d'afficher ta fenetre (qui ne serait du coup
affichée qu'a la fin de l'appel au service web). Donc je pense que lors de
tes tests, le timer a tické avant que l'appel au web service n'ai
réellement commencé ou alors lorsqu'il était déja terminé. Ce qui n'est
pas
ce que tu cherche a faire je pense.
Dans tout les cas, ton approche ne me semble pas etre la bonne. La regle
d'or pour les applis Windows (c'est dans la doc): tout ce qui a trait a
l'UI doit se faire dans un et un seul thread (le thread principal). Sinon,
bugs bizarres quasiment certains (d'ou mon commentaire sur ta premiere
solution). De plus, toute opération longue et bloquante doit etre évitée
dans le thread principal (celui de l'UI) afin d'éviter que ton appli ne
soit gelée. Donc la solution est: lance l'appel a ton web service de
maniere asychrone en passant l'adresse d'une fonction callback a appeler
lorsque l'appel sera terminé; puis démarre ton Timer; puis dans ta
fonction
callback ferme la fenetre d'attente si elle a été affichée.
Bonjour,
Stephane TUET wrote:Ok, c'est vrai que c'est beaucoup plus élégant comme méthode... Par
contre, c'était justement parce que l'appli se retrouve "gelée" que
je voulais afficher ce message d'attente...
En fait , le c'est le thread principal de l'application qui a gére
l'affichage et qui doit attendre le retour du service web et donc "gèle"
l'application.En mode asynchrone, je
suppose que l'utilisateur pourrait faire tout et n'importe quoi
pendant l'appel au service web, ce qui peut parfois être embétant...
Imaginons par exemple que l'utilisateur soit en train de créer un
fournisseur, l'enregistrement de celui-ci se fait via un service web,
et en mode asynchrone, l'utilisateur se retrouve à pouvoir faire des
modifs alors que l'enregistrement est en cours, c'est pas top je
trouve
Les bases de données gère tout ça très bien. Il faut simplement gérer
correctement les exceptions qu'elles peuvent remonter dans ces cas.
Si on reprend votre exemple avec non pas un mais deux utilisateurs, votre
solution ne protège en rien le fait qu'un utilisateur peut agir sur le
même enregistrement qu'un autre utilisateur. L'intérêt est donc assez
limité.(mais y'a sûrement un autre moyen d'éviter cela...). En fait
ma question reviendrait plutôt à quelque chose du genre : tout les
appels à des services web ne peuvent pas forcément se faire en mode
asynchrone, et donc comment faire dans ce cas là ? (si je dis
n'importe quoi je m'en excuse d'avance :-) )
Hmmm, pas certain de bien comprendre la question. Pour les besoins
spécifiques tels que les appels dans des contextes transactionnels, il fut
en passer par les extensions proposées dans le WSE Toolkit.
HTH,
--
Christophe Lauer - Relations Techniques Editeurs de Logiciels
Division Développeurs et Plateforme d'Entreprise - Microsoft France
http://www.microsoft.com/france/msdn/
This posting is provided "AS IS" with no warranties, and confers no
rights.
Bonjour,
Stephane TUET wrote:
Ok, c'est vrai que c'est beaucoup plus élégant comme méthode... Par
contre, c'était justement parce que l'appli se retrouve "gelée" que
je voulais afficher ce message d'attente...
En fait , le c'est le thread principal de l'application qui a gére
l'affichage et qui doit attendre le retour du service web et donc "gèle"
l'application.
En mode asynchrone, je
suppose que l'utilisateur pourrait faire tout et n'importe quoi
pendant l'appel au service web, ce qui peut parfois être embétant...
Imaginons par exemple que l'utilisateur soit en train de créer un
fournisseur, l'enregistrement de celui-ci se fait via un service web,
et en mode asynchrone, l'utilisateur se retrouve à pouvoir faire des
modifs alors que l'enregistrement est en cours, c'est pas top je
trouve
Les bases de données gère tout ça très bien. Il faut simplement gérer
correctement les exceptions qu'elles peuvent remonter dans ces cas.
Si on reprend votre exemple avec non pas un mais deux utilisateurs, votre
solution ne protège en rien le fait qu'un utilisateur peut agir sur le
même enregistrement qu'un autre utilisateur. L'intérêt est donc assez
limité.
(mais y'a sûrement un autre moyen d'éviter cela...). En fait
ma question reviendrait plutôt à quelque chose du genre : tout les
appels à des services web ne peuvent pas forcément se faire en mode
asynchrone, et donc comment faire dans ce cas là ? (si je dis
n'importe quoi je m'en excuse d'avance :-) )
Hmmm, pas certain de bien comprendre la question. Pour les besoins
spécifiques tels que les appels dans des contextes transactionnels, il fut
en passer par les extensions proposées dans le WSE Toolkit.
HTH,
--
Christophe Lauer - Relations Techniques Editeurs de Logiciels
Division Développeurs et Plateforme d'Entreprise - Microsoft France
http://www.microsoft.com/france/msdn/
This posting is provided "AS IS" with no warranties, and confers no
rights.
Bonjour,
Stephane TUET wrote:Ok, c'est vrai que c'est beaucoup plus élégant comme méthode... Par
contre, c'était justement parce que l'appli se retrouve "gelée" que
je voulais afficher ce message d'attente...
En fait , le c'est le thread principal de l'application qui a gére
l'affichage et qui doit attendre le retour du service web et donc "gèle"
l'application.En mode asynchrone, je
suppose que l'utilisateur pourrait faire tout et n'importe quoi
pendant l'appel au service web, ce qui peut parfois être embétant...
Imaginons par exemple que l'utilisateur soit en train de créer un
fournisseur, l'enregistrement de celui-ci se fait via un service web,
et en mode asynchrone, l'utilisateur se retrouve à pouvoir faire des
modifs alors que l'enregistrement est en cours, c'est pas top je
trouve
Les bases de données gère tout ça très bien. Il faut simplement gérer
correctement les exceptions qu'elles peuvent remonter dans ces cas.
Si on reprend votre exemple avec non pas un mais deux utilisateurs, votre
solution ne protège en rien le fait qu'un utilisateur peut agir sur le
même enregistrement qu'un autre utilisateur. L'intérêt est donc assez
limité.(mais y'a sûrement un autre moyen d'éviter cela...). En fait
ma question reviendrait plutôt à quelque chose du genre : tout les
appels à des services web ne peuvent pas forcément se faire en mode
asynchrone, et donc comment faire dans ce cas là ? (si je dis
n'importe quoi je m'en excuse d'avance :-) )
Hmmm, pas certain de bien comprendre la question. Pour les besoins
spécifiques tels que les appels dans des contextes transactionnels, il fut
en passer par les extensions proposées dans le WSE Toolkit.
HTH,
--
Christophe Lauer - Relations Techniques Editeurs de Logiciels
Division Développeurs et Plateforme d'Entreprise - Microsoft France
http://www.microsoft.com/france/msdn/
This posting is provided "AS IS" with no warranties, and confers no
rights.
Je ne comprends pas pourquoi la fenetre sera detruite lors de la fin du
thread !
On ne fait qu'executer une méthode sur une instance globale ..
L'instance de la form n'est pas déclaré dans le thread donc ne doit pas etre
détruite !
Je ne comprends pas pourquoi la fenetre sera detruite lors de la fin du
thread !
On ne fait qu'executer une méthode sur une instance globale ..
L'instance de la form n'est pas déclaré dans le thread donc ne doit pas etre
détruite !
Je ne comprends pas pourquoi la fenetre sera detruite lors de la fin du
thread !
On ne fait qu'executer une méthode sur une instance globale ..
L'instance de la form n'est pas déclaré dans le thread donc ne doit pas etre
détruite !
Par contre, mon
application est en fenêtre MDI, donc la fenêtre d'attente, si je l'affiche
en modale, ça sera au niveau de la fenêtre principale, et ça revient à
bloquer mon application pendant le traitement ! Et donc finalement je me
retrouve avec un mode de fonctionnement équivalent au mode synchrone...
(c'est pas que je revendique le mode synchrone, mais j'ai du mal à
comprendre... :-) )
Par contre, mon
application est en fenêtre MDI, donc la fenêtre d'attente, si je l'affiche
en modale, ça sera au niveau de la fenêtre principale, et ça revient à
bloquer mon application pendant le traitement ! Et donc finalement je me
retrouve avec un mode de fonctionnement équivalent au mode synchrone...
(c'est pas que je revendique le mode synchrone, mais j'ai du mal à
comprendre... :-) )
Par contre, mon
application est en fenêtre MDI, donc la fenêtre d'attente, si je l'affiche
en modale, ça sera au niveau de la fenêtre principale, et ça revient à
bloquer mon application pendant le traitement ! Et donc finalement je me
retrouve avec un mode de fonctionnement équivalent au mode synchrone...
(c'est pas que je revendique le mode synchrone, mais j'ai du mal à
comprendre... :-) )
> Mmm, si tu veux bloquer un de tes fenetres Mdi et laisser l'utilisateur la
possibilité d'utiliser les autres, alors tu pourrai désactiver ta fenetre
Mdi (pour empecher l'utilisateur de cliquer dedans) et afficher un Panel
par dessus avec un message d'attente par exemple. Cela dit est tu sur
qu'il
ne serai pas plus judicieux de tout simplement désaciver le boutton
permettant d'envoyer la requete au service Web mais de laisser
l'utilisateur faire ce qu'il veux dans la fenetre. Apres tout, pourquoi ne
pourrai t'il pas s'amuser a faire d'autre modifications pendant que les
précédentes sont en train d'etre envoyées au service web. La seule chose
importante est que ces modifs soient envoyées dans l'ordre ou elles ont
été
faites (d'ou la désactivation du boutton Envoyer pendant l'appel au
service
Web).
> Mmm, si tu veux bloquer un de tes fenetres Mdi et laisser l'utilisateur la
possibilité d'utiliser les autres, alors tu pourrai désactiver ta fenetre
Mdi (pour empecher l'utilisateur de cliquer dedans) et afficher un Panel
par dessus avec un message d'attente par exemple. Cela dit est tu sur
qu'il
ne serai pas plus judicieux de tout simplement désaciver le boutton
permettant d'envoyer la requete au service Web mais de laisser
l'utilisateur faire ce qu'il veux dans la fenetre. Apres tout, pourquoi ne
pourrai t'il pas s'amuser a faire d'autre modifications pendant que les
précédentes sont en train d'etre envoyées au service web. La seule chose
importante est que ces modifs soient envoyées dans l'ordre ou elles ont
été
faites (d'ou la désactivation du boutton Envoyer pendant l'appel au
service
Web).
> Mmm, si tu veux bloquer un de tes fenetres Mdi et laisser l'utilisateur la
possibilité d'utiliser les autres, alors tu pourrai désactiver ta fenetre
Mdi (pour empecher l'utilisateur de cliquer dedans) et afficher un Panel
par dessus avec un message d'attente par exemple. Cela dit est tu sur
qu'il
ne serai pas plus judicieux de tout simplement désaciver le boutton
permettant d'envoyer la requete au service Web mais de laisser
l'utilisateur faire ce qu'il veux dans la fenetre. Apres tout, pourquoi ne
pourrai t'il pas s'amuser a faire d'autre modifications pendant que les
précédentes sont en train d'etre envoyées au service web. La seule chose
importante est que ces modifs soient envoyées dans l'ordre ou elles ont
été
faites (d'ou la désactivation du boutton Envoyer pendant l'appel au
service
Web).
Je pense donc que je vais revenir sur mon idée de départ (même si les votres
me semblent très bonnes également, le prenez pas mal :-) ). J'arrive presque
à réaliser ce que je veux avec le code suivant (TimerWait étant maintenant
un System.Timers.Timer) :
Private Sub TimerWait_Elapsed(ByVal sender As Object, ByVal e As
System.Timers.ElapsedEventArgs) Handles TimerWait.Elapsed
TimerWait.Stop()
frm_wait.ShowDialog()
End Sub
Public Sub FinAttente()
TimerWait.Stop()
frm_wait.Hide()
End Sub
Mon seul problème maintenant est que si FinAttente intervient pendant le
ShowDialog, le Hide intervient avant que la fenêtre soit complètement
ouverte et donc, elle se réouvre... Mais je ne sais pas comment faire pour
éviter cela... Peut être ajouter un booléen qui indiquerait à ma fenêtre
qu'à la fin de son ouverture, il faut qu'elle se referme ;-)
En tout cas je tiens à vous remercier pour votre aide et toutes vos
explications, j'en tiendrai compte pour mes prochains développements :-)
Je pense donc que je vais revenir sur mon idée de départ (même si les votres
me semblent très bonnes également, le prenez pas mal :-) ). J'arrive presque
à réaliser ce que je veux avec le code suivant (TimerWait étant maintenant
un System.Timers.Timer) :
Private Sub TimerWait_Elapsed(ByVal sender As Object, ByVal e As
System.Timers.ElapsedEventArgs) Handles TimerWait.Elapsed
TimerWait.Stop()
frm_wait.ShowDialog()
End Sub
Public Sub FinAttente()
TimerWait.Stop()
frm_wait.Hide()
End Sub
Mon seul problème maintenant est que si FinAttente intervient pendant le
ShowDialog, le Hide intervient avant que la fenêtre soit complètement
ouverte et donc, elle se réouvre... Mais je ne sais pas comment faire pour
éviter cela... Peut être ajouter un booléen qui indiquerait à ma fenêtre
qu'à la fin de son ouverture, il faut qu'elle se referme ;-)
En tout cas je tiens à vous remercier pour votre aide et toutes vos
explications, j'en tiendrai compte pour mes prochains développements :-)
Je pense donc que je vais revenir sur mon idée de départ (même si les votres
me semblent très bonnes également, le prenez pas mal :-) ). J'arrive presque
à réaliser ce que je veux avec le code suivant (TimerWait étant maintenant
un System.Timers.Timer) :
Private Sub TimerWait_Elapsed(ByVal sender As Object, ByVal e As
System.Timers.ElapsedEventArgs) Handles TimerWait.Elapsed
TimerWait.Stop()
frm_wait.ShowDialog()
End Sub
Public Sub FinAttente()
TimerWait.Stop()
frm_wait.Hide()
End Sub
Mon seul problème maintenant est que si FinAttente intervient pendant le
ShowDialog, le Hide intervient avant que la fenêtre soit complètement
ouverte et donc, elle se réouvre... Mais je ne sais pas comment faire pour
éviter cela... Peut être ajouter un booléen qui indiquerait à ma fenêtre
qu'à la fin de son ouverture, il faut qu'elle se referme ;-)
En tout cas je tiens à vous remercier pour votre aide et toutes vos
explications, j'en tiendrai compte pour mes prochains développements :-)
On Fri, 7 Jan 2005 12:19:20 +0100, Stephane TUET wrote:Je pense donc que je vais revenir sur mon idée de départ (même si les
votres
me semblent très bonnes également, le prenez pas mal :-) ). J'arrive
presque
à réaliser ce que je veux avec le code suivant (TimerWait étant
maintenant
un System.Timers.Timer) :
Fait gaffe avec le System.Timers.Timer. Au contraire du
System.Windows.Form.Timer, la fonction exécutée lors du tick l'est dans un
nouveau thread et non pas dans le thread principal. Lit ma réponse a Pyroa
pour avoir une idée du probleme.Private Sub TimerWait_Elapsed(ByVal sender As Object, ByVal e As
System.Timers.ElapsedEventArgs) Handles TimerWait.Elapsed
TimerWait.Stop()
frm_wait.ShowDialog()
End Sub
Donc voila le probleme. Cette fonction s'exécute dans un thread différent
du thread principal. Tu appele ShowDialog sur une fenetre créé dans un
autre thread -> tu va tres probablement te retrouver un jour avec des bugs
a la con. Le truc marrant dans ces histoires d'acces a des controles
depuis
différents thread, c'est que parfois (le plus souvent en fait) ca marche,
et parfois ca plante. Donc je suis sur que lors des tes tests, tout
fonctionne bien. Et puis un beau jour, un de tes clients t'appelera pour
te
dire que ton appli passe son temps a planter lors de l'appel au service
Web. Et bon courage pour en trouver la raison.
Donc corrige le bug des maintenant: ne cree pas ta fenetre d'attente a
l'avance (dans le thread principal) mais crée la dans ta fonction
TimerWait_Elapsed. Du coup, ta fenetre sera crée et accédée dans un et
unique thread.Public Sub FinAttente()
TimerWait.Stop()
frm_wait.Hide()
End Sub
Si tu applique mon conseil donné au dessus tu va te retrouver avec un
probleme la aussi car ta fonction FinAttente() s'exécute elle dans le
thread principal et tu ne peux donc pas appeler Hide sans t'exposer a des
problemes certains. A la place, utilise la methode Invoke de ta fenetre
d'attente pour marshaller l'appel a Hide vers le second thread.Mon seul problème maintenant est que si FinAttente intervient pendant le
ShowDialog, le Hide intervient avant que la fenêtre soit complètement
ouverte et donc, elle se réouvre... Mais je ne sais pas comment faire
pour
éviter cela... Peut être ajouter un booléen qui indiquerait à ma fenêtre
qu'à la fin de son ouverture, il faut qu'elle se referme ;-)
Une méthode qui marche sans etre peut etre tres propre:
1)déclare un booléen appelTerminé (variable membre de ta classe)
initialisé
a false.
2) Met le contenu de tes fonctions TimerWait_Elapsed et FinAttente() dans
un lock (lock sur le meme objet bien sur). Du coup, une seule de ces
fonction pourra s'exécuter a un moment donné.
3) Dans TimerWait_Elapsed, a l'intérieur du lock, vérifie la valeur de
appelTerminé. Si c'est a true, ne fait rien. Sinon, stoppe le timer et
affiche la fenetre d'attente.
4) Dans FinAttente(), a l'intérieur du lock met appelTerminé a true.
Ca devrait marcher.
En tout cas je tiens à vous remercier pour votre aide et toutes vos
explications, j'en tiendrai compte pour mes prochains développements :-)
On peut se tutoyer hein, ca m'évitera d'avoir l'impression d'etre un vioc
:-)
On Fri, 7 Jan 2005 12:19:20 +0100, Stephane TUET wrote:
Je pense donc que je vais revenir sur mon idée de départ (même si les
votres
me semblent très bonnes également, le prenez pas mal :-) ). J'arrive
presque
à réaliser ce que je veux avec le code suivant (TimerWait étant
maintenant
un System.Timers.Timer) :
Fait gaffe avec le System.Timers.Timer. Au contraire du
System.Windows.Form.Timer, la fonction exécutée lors du tick l'est dans un
nouveau thread et non pas dans le thread principal. Lit ma réponse a Pyroa
pour avoir une idée du probleme.
Private Sub TimerWait_Elapsed(ByVal sender As Object, ByVal e As
System.Timers.ElapsedEventArgs) Handles TimerWait.Elapsed
TimerWait.Stop()
frm_wait.ShowDialog()
End Sub
Donc voila le probleme. Cette fonction s'exécute dans un thread différent
du thread principal. Tu appele ShowDialog sur une fenetre créé dans un
autre thread -> tu va tres probablement te retrouver un jour avec des bugs
a la con. Le truc marrant dans ces histoires d'acces a des controles
depuis
différents thread, c'est que parfois (le plus souvent en fait) ca marche,
et parfois ca plante. Donc je suis sur que lors des tes tests, tout
fonctionne bien. Et puis un beau jour, un de tes clients t'appelera pour
te
dire que ton appli passe son temps a planter lors de l'appel au service
Web. Et bon courage pour en trouver la raison.
Donc corrige le bug des maintenant: ne cree pas ta fenetre d'attente a
l'avance (dans le thread principal) mais crée la dans ta fonction
TimerWait_Elapsed. Du coup, ta fenetre sera crée et accédée dans un et
unique thread.
Public Sub FinAttente()
TimerWait.Stop()
frm_wait.Hide()
End Sub
Si tu applique mon conseil donné au dessus tu va te retrouver avec un
probleme la aussi car ta fonction FinAttente() s'exécute elle dans le
thread principal et tu ne peux donc pas appeler Hide sans t'exposer a des
problemes certains. A la place, utilise la methode Invoke de ta fenetre
d'attente pour marshaller l'appel a Hide vers le second thread.
Mon seul problème maintenant est que si FinAttente intervient pendant le
ShowDialog, le Hide intervient avant que la fenêtre soit complètement
ouverte et donc, elle se réouvre... Mais je ne sais pas comment faire
pour
éviter cela... Peut être ajouter un booléen qui indiquerait à ma fenêtre
qu'à la fin de son ouverture, il faut qu'elle se referme ;-)
Une méthode qui marche sans etre peut etre tres propre:
1)déclare un booléen appelTerminé (variable membre de ta classe)
initialisé
a false.
2) Met le contenu de tes fonctions TimerWait_Elapsed et FinAttente() dans
un lock (lock sur le meme objet bien sur). Du coup, une seule de ces
fonction pourra s'exécuter a un moment donné.
3) Dans TimerWait_Elapsed, a l'intérieur du lock, vérifie la valeur de
appelTerminé. Si c'est a true, ne fait rien. Sinon, stoppe le timer et
affiche la fenetre d'attente.
4) Dans FinAttente(), a l'intérieur du lock met appelTerminé a true.
Ca devrait marcher.
En tout cas je tiens à vous remercier pour votre aide et toutes vos
explications, j'en tiendrai compte pour mes prochains développements :-)
On peut se tutoyer hein, ca m'évitera d'avoir l'impression d'etre un vioc
:-)
On Fri, 7 Jan 2005 12:19:20 +0100, Stephane TUET wrote:Je pense donc que je vais revenir sur mon idée de départ (même si les
votres
me semblent très bonnes également, le prenez pas mal :-) ). J'arrive
presque
à réaliser ce que je veux avec le code suivant (TimerWait étant
maintenant
un System.Timers.Timer) :
Fait gaffe avec le System.Timers.Timer. Au contraire du
System.Windows.Form.Timer, la fonction exécutée lors du tick l'est dans un
nouveau thread et non pas dans le thread principal. Lit ma réponse a Pyroa
pour avoir une idée du probleme.Private Sub TimerWait_Elapsed(ByVal sender As Object, ByVal e As
System.Timers.ElapsedEventArgs) Handles TimerWait.Elapsed
TimerWait.Stop()
frm_wait.ShowDialog()
End Sub
Donc voila le probleme. Cette fonction s'exécute dans un thread différent
du thread principal. Tu appele ShowDialog sur une fenetre créé dans un
autre thread -> tu va tres probablement te retrouver un jour avec des bugs
a la con. Le truc marrant dans ces histoires d'acces a des controles
depuis
différents thread, c'est que parfois (le plus souvent en fait) ca marche,
et parfois ca plante. Donc je suis sur que lors des tes tests, tout
fonctionne bien. Et puis un beau jour, un de tes clients t'appelera pour
te
dire que ton appli passe son temps a planter lors de l'appel au service
Web. Et bon courage pour en trouver la raison.
Donc corrige le bug des maintenant: ne cree pas ta fenetre d'attente a
l'avance (dans le thread principal) mais crée la dans ta fonction
TimerWait_Elapsed. Du coup, ta fenetre sera crée et accédée dans un et
unique thread.Public Sub FinAttente()
TimerWait.Stop()
frm_wait.Hide()
End Sub
Si tu applique mon conseil donné au dessus tu va te retrouver avec un
probleme la aussi car ta fonction FinAttente() s'exécute elle dans le
thread principal et tu ne peux donc pas appeler Hide sans t'exposer a des
problemes certains. A la place, utilise la methode Invoke de ta fenetre
d'attente pour marshaller l'appel a Hide vers le second thread.Mon seul problème maintenant est que si FinAttente intervient pendant le
ShowDialog, le Hide intervient avant que la fenêtre soit complètement
ouverte et donc, elle se réouvre... Mais je ne sais pas comment faire
pour
éviter cela... Peut être ajouter un booléen qui indiquerait à ma fenêtre
qu'à la fin de son ouverture, il faut qu'elle se referme ;-)
Une méthode qui marche sans etre peut etre tres propre:
1)déclare un booléen appelTerminé (variable membre de ta classe)
initialisé
a false.
2) Met le contenu de tes fonctions TimerWait_Elapsed et FinAttente() dans
un lock (lock sur le meme objet bien sur). Du coup, une seule de ces
fonction pourra s'exécuter a un moment donné.
3) Dans TimerWait_Elapsed, a l'intérieur du lock, vérifie la valeur de
appelTerminé. Si c'est a true, ne fait rien. Sinon, stoppe le timer et
affiche la fenetre d'attente.
4) Dans FinAttente(), a l'intérieur du lock met appelTerminé a true.
Ca devrait marcher.
En tout cas je tiens à vous remercier pour votre aide et toutes vos
explications, j'en tiendrai compte pour mes prochains développements :-)
On peut se tutoyer hein, ca m'évitera d'avoir l'impression d'etre un vioc
:-)
Private Sub TimerWait_Elapsed(ByVal sender As Object, ByVal e As
System.Timers.ElapsedEventArgs) Handles TimerWait.Elapsed
lock.Enter(objLock)
If Not AppelTermine Then
TimerWait.Stop()
frm_wait = New FRM_Wait
frm_wait.ShowDialog()
End If
lock.Exit(objLock)
End Sub
Maintenant, d'abord ce que je ne comprends pas :-) : Comment le
lock.Exit(objLock) de TimerWait_Elapsed peut être exécuté alors qu'il est
après un showdialog ?
Ensuite, apparemment j'ai toujours le même problème puisque dans certains
cas j'obtiens l'erreur suivante :
Cannot call Invoke or InvokeAsync on a control until the window handle has
been created.
C'est à dire quand FinAttente arrive alors que la fenêtre d'attente est en
cours d'ouverture (je suppose).
Private Sub TimerWait_Elapsed(ByVal sender As Object, ByVal e As
System.Timers.ElapsedEventArgs) Handles TimerWait.Elapsed
lock.Enter(objLock)
If Not AppelTermine Then
TimerWait.Stop()
frm_wait = New FRM_Wait
frm_wait.ShowDialog()
End If
lock.Exit(objLock)
End Sub
Maintenant, d'abord ce que je ne comprends pas :-) : Comment le
lock.Exit(objLock) de TimerWait_Elapsed peut être exécuté alors qu'il est
après un showdialog ?
Ensuite, apparemment j'ai toujours le même problème puisque dans certains
cas j'obtiens l'erreur suivante :
Cannot call Invoke or InvokeAsync on a control until the window handle has
been created.
C'est à dire quand FinAttente arrive alors que la fenêtre d'attente est en
cours d'ouverture (je suppose).
Private Sub TimerWait_Elapsed(ByVal sender As Object, ByVal e As
System.Timers.ElapsedEventArgs) Handles TimerWait.Elapsed
lock.Enter(objLock)
If Not AppelTermine Then
TimerWait.Stop()
frm_wait = New FRM_Wait
frm_wait.ShowDialog()
End If
lock.Exit(objLock)
End Sub
Maintenant, d'abord ce que je ne comprends pas :-) : Comment le
lock.Exit(objLock) de TimerWait_Elapsed peut être exécuté alors qu'il est
après un showdialog ?
Ensuite, apparemment j'ai toujours le même problème puisque dans certains
cas j'obtiens l'erreur suivante :
Cannot call Invoke or InvokeAsync on a control until the window handle has
been created.
C'est à dire quand FinAttente arrive alors que la fenêtre d'attente est en
cours d'ouverture (je suppose).
On Fri, 7 Jan 2005 15:35:35 +0100, Stephane TUET wrote:Private Sub TimerWait_Elapsed(ByVal sender As Object, ByVal e As
System.Timers.ElapsedEventArgs) Handles TimerWait.Elapsed
lock.Enter(objLock)
If Not AppelTermine Then
TimerWait.Stop()
frm_wait = New FRM_Wait
frm_wait.ShowDialog()
End If
lock.Exit(objLock)
End SubMaintenant, d'abord ce que je ne comprends pas :-) : Comment le
lock.Exit(objLock) de TimerWait_Elapsed peut être exécuté alors qu'il est
après un showdialog ?
Bon d'accord, j'ai honte, surtout apres tout le temps que j'ai passé a
m'amuser avec threads et autres joyeusetés du meme genre. Effectivement,
le
lock n'est jamais relaché. Théoriquement, tu devrais avoir un deadlock vu
que que pour fermer ta fenetre tu doit acquérir le lock qui n'est relaché
que lorsque la fenetre sera fermée (donc appli gelée indéfiniment).
Maintenant tu va me dire que non, il n'y a pas de deadlock puisque tu a
essayé et que l'appli n'était pas gelée. Et c'est la qu'arrive un des
subtilités du Monitor.Enter. Dans la doc de cette fonction, tu va trouver:
"Use Monitor to lock objects (that is, reference types), not value types.
When you pass a value type variable to Enter, it is boxed as an object. If
you pass the same variable to Enter again, it is boxed as a separate
object, and the thread does not block."
Tu utilise un Integer comme lock. C'est un "value type". Donc a chaque
fois
que tu appele Enter sur ton Integer, le lock s'effectue sur un nouvel
objet. Autrement, ton lock ne sert a rien. Remplace:
Private objLock As Integer
par
Private objLock As New Object
Execute maintenant ton appli et ca va bloquer (car Object est un
"reference
type" donc tu lock toujours sur le meme objet).Ensuite, apparemment j'ai toujours le même problème puisque dans certains
cas j'obtiens l'erreur suivante :
Cannot call Invoke or InvokeAsync on a control until the window handle
has
been created.
C'est à dire quand FinAttente arrive alors que la fenêtre d'attente est
en
cours d'ouverture (je suppose).
Oui vu qu'en fait ton lock ne fonctionnait pas donc tu était dans la meme
situation qu'avant.
Reste que ca ne résout pas ton probleme. Et la je seche. Si je trouve un
truc, je te le dirai mais la je vois pas.
On Fri, 7 Jan 2005 15:35:35 +0100, Stephane TUET wrote:
Private Sub TimerWait_Elapsed(ByVal sender As Object, ByVal e As
System.Timers.ElapsedEventArgs) Handles TimerWait.Elapsed
lock.Enter(objLock)
If Not AppelTermine Then
TimerWait.Stop()
frm_wait = New FRM_Wait
frm_wait.ShowDialog()
End If
lock.Exit(objLock)
End Sub
Maintenant, d'abord ce que je ne comprends pas :-) : Comment le
lock.Exit(objLock) de TimerWait_Elapsed peut être exécuté alors qu'il est
après un showdialog ?
Bon d'accord, j'ai honte, surtout apres tout le temps que j'ai passé a
m'amuser avec threads et autres joyeusetés du meme genre. Effectivement,
le
lock n'est jamais relaché. Théoriquement, tu devrais avoir un deadlock vu
que que pour fermer ta fenetre tu doit acquérir le lock qui n'est relaché
que lorsque la fenetre sera fermée (donc appli gelée indéfiniment).
Maintenant tu va me dire que non, il n'y a pas de deadlock puisque tu a
essayé et que l'appli n'était pas gelée. Et c'est la qu'arrive un des
subtilités du Monitor.Enter. Dans la doc de cette fonction, tu va trouver:
"Use Monitor to lock objects (that is, reference types), not value types.
When you pass a value type variable to Enter, it is boxed as an object. If
you pass the same variable to Enter again, it is boxed as a separate
object, and the thread does not block."
Tu utilise un Integer comme lock. C'est un "value type". Donc a chaque
fois
que tu appele Enter sur ton Integer, le lock s'effectue sur un nouvel
objet. Autrement, ton lock ne sert a rien. Remplace:
Private objLock As Integer
par
Private objLock As New Object
Execute maintenant ton appli et ca va bloquer (car Object est un
"reference
type" donc tu lock toujours sur le meme objet).
Ensuite, apparemment j'ai toujours le même problème puisque dans certains
cas j'obtiens l'erreur suivante :
Cannot call Invoke or InvokeAsync on a control until the window handle
has
been created.
C'est à dire quand FinAttente arrive alors que la fenêtre d'attente est
en
cours d'ouverture (je suppose).
Oui vu qu'en fait ton lock ne fonctionnait pas donc tu était dans la meme
situation qu'avant.
Reste que ca ne résout pas ton probleme. Et la je seche. Si je trouve un
truc, je te le dirai mais la je vois pas.
On Fri, 7 Jan 2005 15:35:35 +0100, Stephane TUET wrote:Private Sub TimerWait_Elapsed(ByVal sender As Object, ByVal e As
System.Timers.ElapsedEventArgs) Handles TimerWait.Elapsed
lock.Enter(objLock)
If Not AppelTermine Then
TimerWait.Stop()
frm_wait = New FRM_Wait
frm_wait.ShowDialog()
End If
lock.Exit(objLock)
End SubMaintenant, d'abord ce que je ne comprends pas :-) : Comment le
lock.Exit(objLock) de TimerWait_Elapsed peut être exécuté alors qu'il est
après un showdialog ?
Bon d'accord, j'ai honte, surtout apres tout le temps que j'ai passé a
m'amuser avec threads et autres joyeusetés du meme genre. Effectivement,
le
lock n'est jamais relaché. Théoriquement, tu devrais avoir un deadlock vu
que que pour fermer ta fenetre tu doit acquérir le lock qui n'est relaché
que lorsque la fenetre sera fermée (donc appli gelée indéfiniment).
Maintenant tu va me dire que non, il n'y a pas de deadlock puisque tu a
essayé et que l'appli n'était pas gelée. Et c'est la qu'arrive un des
subtilités du Monitor.Enter. Dans la doc de cette fonction, tu va trouver:
"Use Monitor to lock objects (that is, reference types), not value types.
When you pass a value type variable to Enter, it is boxed as an object. If
you pass the same variable to Enter again, it is boxed as a separate
object, and the thread does not block."
Tu utilise un Integer comme lock. C'est un "value type". Donc a chaque
fois
que tu appele Enter sur ton Integer, le lock s'effectue sur un nouvel
objet. Autrement, ton lock ne sert a rien. Remplace:
Private objLock As Integer
par
Private objLock As New Object
Execute maintenant ton appli et ca va bloquer (car Object est un
"reference
type" donc tu lock toujours sur le meme objet).Ensuite, apparemment j'ai toujours le même problème puisque dans certains
cas j'obtiens l'erreur suivante :
Cannot call Invoke or InvokeAsync on a control until the window handle
has
been created.
C'est à dire quand FinAttente arrive alors que la fenêtre d'attente est
en
cours d'ouverture (je suppose).
Oui vu qu'en fait ton lock ne fonctionnait pas donc tu était dans la meme
situation qu'avant.
Reste que ca ne résout pas ton probleme. Et la je seche. Si je trouve un
truc, je te le dirai mais la je vois pas.