PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : C# Timer trouble


minos5000
2013-07-11, 13:46:18
Hi,

in einem Programm soll eine Form nach Ausführen eines Befehls für 2 sek angezeigt werden, wofür ich einen Timer verwende.

Die Codeschnippsel sehen so aus:


private const int INTERVAL = 2000;
private System.Timers.Timer timer;

timer = new System.Timers.Timer();
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
timer.Interval = INTERVAL;


void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
timerRunning = false;
this.Hide();
}


internal void ActivateForm()
{
this.BringToFront();
this.Show();
this.Refresh();
if (!timerRunning)
{
timerRunning = true;
timer.Start();
}
else
timer.Interval = INTERVAL;
}


In 9 von 10 Fällen funktioniert das ganze auch wie es soll, aber gelegentlich wird die Form deutlich zu kurz angezeigt. Flackert praktisch nur kurz auf.

Wie kann das sein?

][immy
2013-07-11, 14:17:02
Benutzt du immer die gleiche Timer-Instanz oder erzeugst du diese immer mit einer Klasse neu?
da fehlt eigentlich ein timer.Stop() und eventuell auch noch ein Timer.Reset bevor du ihn startest.

Exxtreme
2013-07-11, 14:18:28
Kann sein, dass der Dialog/die Form gleich wieder überdeckt wird?

minos5000
2013-07-11, 19:41:02
[immy;9839144']Benutzt du immer die gleiche Timer-Instanz oder erzeugst du diese immer mit einer Klasse neu?
da fehlt eigentlich ein timer.Stop() und eventuell auch noch ein Timer.Reset bevor du ihn startest.

Instanz ist immer die gleiche und Stop und Reset hatte ich bislang nicht drin weil es keine Situation gibt, in der der Timer vor der 2 sek Marke abgebrochen werden soll. Habe aber gerade gesehen, dass es auch ein Flag AutoReset gibt. Werde etwas damit herumspielen, vielleicht findet sich ja eine Konstellation in der das Problem nicht aufritt.

Kann sein, dass der Dialog/die Form gleich wieder überdeckt wird?

Wäre schön, wenn es so einfach wäre, aber das kann ich ausschließen, da die Form eh schon topmost ist und sich das Verhalten auch zeigt, wenn sonst keinerlei Fenster offen sind.

Trap
2013-07-11, 19:52:19
Die ganzen Sonderfälle unter "Remarks" in http://msdn.microsoft.com/en-us/library/system.timers.timer.elapsed.aspx kennst du?

PatkIllA
2013-07-11, 19:55:36
Das Elapsed Event kommt doch auch aus einem anderen Thread. Das mögen die GUI-Frameworks nicht so wirklich. Eigentlich müsste da im Debug sogar eine Fehlermeldung kommen, wenn du nicht Control.CheckForIllegalCrossThreadCalls = false setzt.

minos5000
2013-07-11, 20:16:42
Die ganzen Sonderfälle unter "Remarks" in http://msdn.microsoft.com/en-us/library/system.timers.timer.elapsed.aspx kennst du?

Ja, die kenne ich, mein Problem ließ sich dadurch zwar nicht erklären, aber scheint als hätte - warum auch immer - ein wohlplatziertes Stop() das Problem behoben :)


void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
timerRunning = false;
timer.Stop();
this.Hide();
}

PatkIllA
2013-07-11, 20:18:58
Ja, die kenne ich, mein Problem ließ sich dadurch zwar nicht erklären, Da kann alles mögliche passieren. Es reicht ja evtl. schon die Maus zu bewegen, um das Form durch zwei Threads durcheinander zu bringen. Da Invoke solltest du dir gönnen.

Marscel
2013-07-11, 20:34:10
Ja, die kenne ich, mein Problem ließ sich dadurch zwar nicht erklären, aber scheint als hätte - warum auch immer - ein wohlplatziertes Stop() das Problem behoben :)

Ja, es scheint so. Wirklich sauber ist nur eine Lösung:

* Kapsel den Timer in eine eigene Klasse: da kommt dann ein eigenes public delegate und ein public event rein.
* Von außen, aus dem Form, registrierst du dann ein Callback auf das Event, das die Delegate-Signatur hat.
* Im Callback führst du dann mittels this.Invoke die GUI-Sachen aus. Mit this.InvokeRequired kann man sogar prüfen, ob man es direkt aufrufen kann (GUI-Thread) oder ob es von extern kommt (z.B. Timer-Thread).

Relay
2013-07-11, 21:36:25
Ja, es scheint so. Wirklich sauber ist nur eine Lösung:

* Kapsel den Timer in eine eigene Klasse: da kommt dann ein eigenes public delegate und ein public event rein.
* Von außen, aus dem Form, registrierst du dann ein Callback auf das Event, das die Delegate-Signatur hat.
* Im Callback führst du dann mittels this.Invoke die GUI-Sachen aus. Mit this.InvokeRequired kann man sogar prüfen, ob man es direkt aufrufen kann (GUI-Thread) oder ob es von extern kommt (z.B. Timer-Thread).

Da er keinerlei Arbeit im Timer-Event-Thread verrichtet sollte er einfach
System.Windows.Forms.Timer verwenden.

@te
Schau mal auf msdn mach der klasse. In deinem anwendungsfall sollte das die beste lösung sein.

][immy
2013-07-12, 00:01:35
Ja, die kenne ich, mein Problem ließ sich dadurch zwar nicht erklären, aber scheint als hätte - warum auch immer - ein wohlplatziertes Stop() das Problem behoben :)


void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
timerRunning = false;
timer.Stop();
this.Hide();
}


dein Problem war wohl, das du den Tuner nicht angehalten hast, d.h. Der feuerte alle 2s das Event. Das mag zwischendurch dann mal gepasst haben, aber dadurch kam es dann wohl dazu, das deine anzeige gleich wieder geschlossen wurde.
bei den controls solltest du aber immer mit ivoke arbeiten um in den hauptthread zu kommen und dort das control dann schließen, den sonst kann dir das ganze gern mal um die ihren fliegen.
die Abfrage von invokerequiered kannst du dir aber sparen, verbraucht weitaus mehr rechenzeit als ein unnötiges invoke.

Wenn du mit mehreren time Instanzen arbeitest solltest du auf keinen fall das Stop() vergessen, denn sonst hast du unnötige hintergrundthreads laufen. Ich meine der Timer implementiert auch IDisposeable, darüber solltest du den also auch stoppen können ( z.b. In dem dispose des zu schließenden controls gleich mit abräumen und im condtructor erzeugen, dann hast du das autoclose gleich damit verdongelt.)