Voor een wat uitgebreide WinForms applicatie heb ik de volgende opzet.
ListenServer (in appart thread) die wacht tot er een bericht komt, zodra er iets binnenkomt wordt dit bericht per event afgehandeld door Program.cs dat zelf weer een event stuurt naar het Form dat een abonnement heeft op dit event.
In dit event wordt vaak een form gesloten en een nieuw form gemaakt. Omdat de code om dit te doen niet in het Thread van Program.cs zit moet dit ge-invoked worden. Dat is natuurlijk allemaal vrij logisch:
Dit gebeurt in het mainForm (nu Program.mainForm).
Daarna wordt via een zelfde delegate in 'currentForm' het eigen scherm gesloten.
Dit gaat de eerste keer goed. Het mainForm blijft gewoon actief (wordt niet gesloten). Uiteindelijk roept een event in het mainform weer dezelfde delegate als helemaal boven aan. Dit gaat ook goed. Het tweede forms' delegate wordt na een tijdje ook aangeroepen, maar nu gaat het fout. Ik krijg de volgende fout:
"Invoke or BeginInvoke cannot be called on a control until the window handle has been created."
Maar dit event dat de delegate triggered gebeurt pas 2,5 seconden nadat ik het form zie (er zelfs op kan klikken enzo). En ik gebruik this, wat niet kan bestaan als het form nog niet helemaal gemaakt is.
Om dit op te loseen heb ik de laatste regel vervangen (na flink wat geklooi).
Nu gaat het 'allemaal' goed, het tweede form wordt weer netjes weergegeven. Maar nu komt het rare, door deze verandering blijft het Form actief op een of andere manier. En er gebeuren allemaal rare dingen, in een van de delegates wordt ++variabele gedaan, en ondanks dat het form al vernietigd moet zijn en opnieuw gecreeerd wordt bij het opnieuw creeeren op een of andere manier toch deze variable weer geset op de allerlaatste waarde. Het lijkt wel alsof variabelen ook aangesproken in delegates worden hergebruikt (ondanks dat er duidelijk new staat in de aanroep van het form). Dit heb ik zelfs met debuggen ondervonden. Ook lijkt het form niet goed gesloten te worden, alsof de delegates het form niet kunnen sluiten.
Op een gegeven moment had ik een video op het form, de eerste keer ging altijd goed maar halverwege de 2e weergave werd telkens het paneel waar de video op zat zomaar gedisposed (was immers gesloten). Is er iets geks met delegates aan de hand waardoor ze geheugen hergebruiken? Ik gebruik nergens unsafe code, en in de aanroep staat echt new. Ik heb een testprogrammatje gemaakt (waar ik nu code uit geciteerd heb). En daar gaat bijna alles ook in fout, behalve dat variabele niet gereset worden. (Het scherm blijft wel actief want het blijft reageren op events.).
Om geen bugs over het hoofd te zien hier nog even de code uit de relevante scherm van het echt programma
Uiteindelijk kom je via frmResult weer terug in het nog openstaande frmDebate, dat via een nieuw frmJoin scherm weer een nieuw frmQuestion aan maakt. Dat nieuwe frmQuestion (dat echt niet gehide werd zoals te zien is). Houd oude variabele en wordt halverwege ineens gedisposed.
Heeft iemand enig idee waar dit rare gedrag door kan komen? (Door dat ik het thread waar Program.cs in draait gebruik misschien?) Waardoor de foutmelding komt. (Al gegoogled, maar daar komt niet echt wat relevants uit). Of nog beter, eigenlijk wil ik van deze hele Thread->Thread->Delegate structuur af. Hoe zorg ik ervoor dat ik (via events) berichten naar mijn forms kan sturen vanaf een appart thread, zonder dat ik via delegates allemaal rare dingen moet doen. Ik kan de berichten wel ergens anders gaan parsen ofzo, mocht dat alles makkelijker maken.
Zelf zie ik het probleem gewoon niet zitten, ook na een dagje denken niet.
ListenServer (in appart thread) die wacht tot er een bericht komt, zodra er iets binnenkomt wordt dit bericht per event afgehandeld door Program.cs dat zelf weer een event stuurt naar het Form dat een abonnement heeft op dit event.
In dit event wordt vaak een form gesloten en een nieuw form gemaakt. Omdat de code om dit te doen niet in het Thread van Program.cs zit moet dit ge-invoked worden. Dat is natuurlijk allemaal vrij logisch:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
| private delegate void VoidDelegate(); private void Program_OnEv() { VoidDelegate j = delegate() { Program.currentForm = new Form2(); Program.currentForm.Show(); Program.OnEv -= Program_OnEv; this.Hide(); }; this.Invoke(j); } |
Dit gebeurt in het mainForm (nu Program.mainForm).
Daarna wordt via een zelfde delegate in 'currentForm' het eigen scherm gesloten.
C#:
1
2
3
4
5
6
7
8
9
10
| private void Program_OnEv() { VoidDelegate j = delegate() { Program.mainForm.Reset(); this.Close(); }; this.invoke(j); } |
Dit gaat de eerste keer goed. Het mainForm blijft gewoon actief (wordt niet gesloten). Uiteindelijk roept een event in het mainform weer dezelfde delegate als helemaal boven aan. Dit gaat ook goed. Het tweede forms' delegate wordt na een tijdje ook aangeroepen, maar nu gaat het fout. Ik krijg de volgende fout:
"Invoke or BeginInvoke cannot be called on a control until the window handle has been created."
Maar dit event dat de delegate triggered gebeurt pas 2,5 seconden nadat ik het form zie (er zelfs op kan klikken enzo). En ik gebruik this, wat niet kan bestaan als het form nog niet helemaal gemaakt is.
Om dit op te loseen heb ik de laatste regel vervangen (na flink wat geklooi).
C#:
1
2
| this.Invoke(j); //oud Program.mainForm.Invoke(j); //nieuw |
Nu gaat het 'allemaal' goed, het tweede form wordt weer netjes weergegeven. Maar nu komt het rare, door deze verandering blijft het Form actief op een of andere manier. En er gebeuren allemaal rare dingen, in een van de delegates wordt ++variabele gedaan, en ondanks dat het form al vernietigd moet zijn en opnieuw gecreeerd wordt bij het opnieuw creeeren op een of andere manier toch deze variable weer geset op de allerlaatste waarde. Het lijkt wel alsof variabelen ook aangesproken in delegates worden hergebruikt (ondanks dat er duidelijk new staat in de aanroep van het form). Dit heb ik zelfs met debuggen ondervonden. Ook lijkt het form niet goed gesloten te worden, alsof de delegates het form niet kunnen sluiten.
Op een gegeven moment had ik een video op het form, de eerste keer ging altijd goed maar halverwege de 2e weergave werd telkens het paneel waar de video op zat zomaar gedisposed (was immers gesloten). Is er iets geks met delegates aan de hand waardoor ze geheugen hergebruiken? Ik gebruik nergens unsafe code, en in de aanroep staat echt new. Ik heb een testprogrammatje gemaakt (waar ik nu code uit geciteerd heb). En daar gaat bijna alles ook in fout, behalve dat variabele niet gereset worden. (Het scherm blijft wel actief want het blijft reageren op events.).
Om geen bugs over het hoofd te zien hier nog even de code uit de relevante scherm van het echt programma
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| //Uit scherm dat het form maakt, wat zelf ook telkens opnieuw gemaakt wordt. DelegateNull j = delegate() { Program.currentForm = new frmQuestion(); Program.currentForm.Show(); timer.Stop(); this.Close(); }; Program.debateForm.Invoke(j); //hoofdscherm dat er altijd is //Uit frmQuestion zelf, dat zichzelf via deze delegate sluit en weer doorgaat naar een ander scherm. DelegateNull j = delegate() { frmResult result = new frmResult(); result.SetResults(message.Substring(8)); Program.currentForm = result; result.Show(); this.Close(); }; Program.debateForm.Invoke(j); |
Uiteindelijk kom je via frmResult weer terug in het nog openstaande frmDebate, dat via een nieuw frmJoin scherm weer een nieuw frmQuestion aan maakt. Dat nieuwe frmQuestion (dat echt niet gehide werd zoals te zien is). Houd oude variabele en wordt halverwege ineens gedisposed.
Heeft iemand enig idee waar dit rare gedrag door kan komen? (Door dat ik het thread waar Program.cs in draait gebruik misschien?) Waardoor de foutmelding komt. (Al gegoogled, maar daar komt niet echt wat relevants uit). Of nog beter, eigenlijk wil ik van deze hele Thread->Thread->Delegate structuur af. Hoe zorg ik ervoor dat ik (via events) berichten naar mijn forms kan sturen vanaf een appart thread, zonder dat ik via delegates allemaal rare dingen moet doen. Ik kan de berichten wel ergens anders gaan parsen ofzo, mocht dat alles makkelijker maken.
Zelf zie ik het probleem gewoon niet zitten, ook na een dagje denken niet.
[ Voor 5% gewijzigd door roy-t op 25-11-2009 22:23 . Reden: Meer info hergebruik variabele die in delegates voorkomen. ]