Frage von ultrabrot123, 43

C# Threading.Sleep Fehler?

Das Problem, das ich nicht verstehe:

Warum zeigt er das Bild und die MessageBox gleichzeitig nach einer Sekunde an und NICHT erst das Bild und dann nach einer Sekunde die MessageBox ?

private void button1_Click(object sender, EventArgs e)
{
    Bild.Visible = true;
    Thread.Sleep(1000);
    MessageBox.Show("Text");
}
Antwort
von KnusperPudding, 27

Bin zwar kein C# Programmierer, aber das "Problem" ist nicht nur da bekannt. 

Warum das so ist, ist relativ einfach: 

Drückst du auf einen Button, wird der GUI-Thread pausiert. Die Anweisung deines Buttons wird ausgeführt und anschließend wird der GUI-Thread fortgesetzt. 

Du könntest es lösen, indem du die beiden Zeilen: Thread.sleep() und Messagebox.show in einem neuen Thread startest. In Java würde das so aussehen:

private void click() {
    bild.setVisible(true);
    new Thread(new Runnable() {

@Override public void run() { Thread.sleep(1000); JOptionPane.showMessageDialog(null, "Text"); } }).start(); }
Antwort
von Kiboman, 26

ich kann mir das nur so erklären.

du hast das using vergessen.

using system.threading;

bekommst einen error und debugst einen build bevor du das sleep eingebaut hast.

Antwort
von CrystalixXx, 13

Eigentlich ist dein Problem relativ einfach zu erklären. An sich hat es nichts mit Threads (auch wenn die Abhilfe schaffen können - je nach Aufgabe) oder der Programmiersprache zu tun, wie manche glauben.

Vorweg: du hättest das selbe Ergebnis, wenn du statt "Thread.Sleep" eine andere Methode aufrufst, die zur Ausführung eine spürbare Zeit in Anspruch nimmt.

Die Ursache liegt in der Message-Queue, die nicht schnell genug verarbeitet wird. Du stellst die Visible-Eigenschaft deines Steuerelementes auf True, wodurch du ein Ereignis auslöst. Bevor das übergeordnete Steuerelement aber seinen Inhalt für ungültig erklärt und neugezeichnet/dargestellt hat (d.h. die Auswirkung deiner Änderung auf Visible = True sichtbar werden) schickst du den Thread bereits in den Schlafmodus.

Eine Lösung wäre zum Beispiel "Bild.Parent.Refresh" oder "Me.Refresh" unmittelbar nach "Bild.Visible = True" zu schreiben. Damit erzwingst du das Neuzeichnen und wartest mit der weiteren Abarbeitung auf Beendigung des Neuzeichnens.

Kommentar von CrystalixXx ,

Kleine Ergänzung:

Application.DoEvents schafft zwar auch Abhilfe, aber wenn man der Meinung ist, man braucht eine solche Anweisung, ist das ein gutes Zeichen für eine falsche Herangehensweise. Dann sollte man lieber über Threads nachdenken - wo dann die Antwort von KnusperPudding ins Spiel kommt.

Kommentar von Requi ,

So weit ich weiß, lässt die Methode "Invalidate();" das Event FormPaint aufrufen, was somit auch zu einem Redrawing resultiert.

Kommentar von CrystalixXx ,

Ja, aber es gibt Unterschiede zwischen Refresh und Invalidate.

Invalidate erklärt das Steuerelement für ungültig und markiert es zum Neuzeichnen. Das Neuzeichnen erfolgt dann, wenn das nächste Mal eine WM_PAINT Anforderung durch die MessageQueue verarbeitet wird. Es wird also nicht sofort neugezeichnet.

Refresh hingegen ruft zwar intern auch die Invalidate-Funktion auf, führt dann aber ein Control.Update aus. Diese Methode sorgt dafür, dass die WM_Paint Anforderung direkt (also ohne den Weg über die MessageQueue) an WNDPROC gesendet und somit das Neuzeichnen ausgelöst wird.

Antwort
von Dominic121219, 27

Mit diesen problemen musst du halt leben. Das selbe ist es in vb, c, c++.. Nur python sieht da meines wissen gut aus und bash, sh..  Die sleep funktion sollte nur am ende einer void, int etc.. Vorkommen

Keine passende Antwort gefunden?

Fragen Sie die Community

Weitere Fragen mit Antworten