2014-03-03 4 views
34

Ich möchte einige Sekunden zwischen zwei Anweisungen warten, OHNE die Ausführung zu blockieren.Warten Sie einige Sekunden, ohne die Ausführung der Benutzeroberfläche zu blockieren

Zum Beispiel Thread.Sleep(2000) ist es nicht gut, weil es die Ausführung blockiert.

Die Idee ist, dass ich eine Methode aufrufen und dann warte ich X Sekunden (20 zum Beispiel) auf ein Ereignis lauschen. Am Ende der 20 Sekunden sollte ich eine Operation durchführen, abhängig davon, was in den 20 Sekunden passiert ist.

+1

Können wir ein Beispiel sehen, was Sie meinen? Das ist sehr breit. – gunr2171

+0

Gibt es außerdem eine Art von Anwendung, die Sie erstellen? Eine Konsole, WPF, Winforms, ASP.NET App oder etwas anderes? – jstromwick

+0

Möchten Sie immer X Sekunden auf das Ereignis warten oder können Sie eine Operation ausführen, sobald das Ereignis kommt und eine andere Operation ausführen, wenn das Ereignis nicht innerhalb von X Sekunden, d. H. Wie eine Zeitüberschreitung, eintritt? – alsed42

Antwort

7

Dies ist ein gutes Beispiel für die Verwendung von einem anderen Thread:

// Call some method 
this.Method(); 

Task.Factory.StartNew(() => 
{ 
    Thread.Sleep(20000); 

    // Do things here. 
    // NOTE: You may need to invoke this to your main thread depending on what you're doing 
}); 

Der obige Code .NET 4.0 oder höher erwartet, sonst versuchen:

ThreadPool.QueueUserWorkItem(new WaitCallback(delegate 
{ 
    Thread.Sleep(20000); 

    // Do things here 
})); 
+3

Ich werde nur einen Kommentar zu meiner eigenen älteren Antwort hier hinzufügen, um zu sagen, dass ich die in anderen Antworten erwähnten asynchronen Methoden bevorzuge, da sie sowohl sauberer als auch besser sind. Wenn Sie Async nicht bereits gelesen haben, empfehle ich Ihnen, dies zu tun. – Matt

0

Blick in System.Threading.Timer Klasse. Ich denke, das ist es wonach Sie suchen.

Die code example on MSDN scheint zu zeigen, dass diese Klasse sehr ähnlich zu dem, was Sie versuchen, tun (Status nach einer bestimmten Zeit überprüfen).

+0

Können Sie eine kleine Probe zur Verfügung stellen? –

+0

@JeroenVannevel Es gibt ein Beispiel in dem Link in meinem Beitrag. Was fehlt mir, um hinzuzufügen? – LB2

+1

@JeroenVannevel Sie sollten ein Beispiel hinzufügen, damit Ihre Antwort auch dann einen Wert liefert, wenn die Verknüpfung ungültig wird. "Look into foobar" bietet auch nur wenig Wert für sich. – sloth

55

Ich denke, was Sie suchen, ist Task.Delay. Dies blockiert nicht den Thread, wie es Sleep tut, und es bedeutet, dass Sie dies mithilfe eines einzelnen Threads mithilfe des asynchronen Programmiermodells tun können.

async Task PutTaskDelay() 
{ 
    await Task.Delay(5000); 
} 

private async void btnTaskDelay_Click(object sender, EventArgs e) 
{ 
    await PutTaskDelay(); 
    MessageBox.Show("I am back"); 
} 
+0

Danke, es scheint interessant. Ich habe nur ein Problem, die Async und warten werden nicht von C# erkannt. Weißt du, warum? – user3376691

+0

Sie sind ziemlich neu im .NET Framework und wurden mit Version 4.5 in Visual Studio 2012 und 2013 hinzugefügt. Es gibt ein nugget-Paket unter http://www.nuget.org/packages/Microsoft.Bcl.Async/ wenn dies der Fall ist hilft. – daniellepelley

+0

Danke. Ich habe Visual Studio Express 2013 installiert und es hat Async und wartet jetzt. Aber wenn die Methode Delay of Task verwendet werden soll, existiert sie nicht. Die einzigen erlaubten Methoden sind Equals, ReferenceEquals, WaitAll und WaitAny ... Weißt du warum? – user3376691

2

i abraten Sie wirklich gegen Thread.Sleep(2000) verwenden, wegen einer aus mehreren Gründen (einige sind here beschrieben), sondern vor allem, weil es ist nicht sinnvoll, wenn es darum geht,/Testen zu Debuggen.

Ich empfehle, eine C# Timer anstelle von Thread.Sleep() zu verwenden. Mit Timern können Sie häufig Methoden ausführen (falls erforderlich) und Sie können sie viel einfacher testen! Es gibt ein sehr schönes Beispiel dafür, wie man einen Timer direkt hinter dem Hyperlink verwendet - setzen Sie einfach Ihre Logik "Was passiert nach 2 Sekunden" in die Timer.Elapsed += new ElapsedEventHandler(OnTimedEvent); Methode.

3

Wenn Sie nicht wollen, Dinge zu blockieren und auch nicht wollen, Multi-Threading verwenden, hier ist die Lösung für Sie: https://msdn.microsoft.com/en-us/library/system.timers.timer(v=vs.110).aspx

der UI-Thread wird für 2 Sekunden nicht blockiert und die Timer-Funktion wartet, bevor etwas zu tun .

Hier kommt der Code aus dem obigen Link:

 // Create a timer with a two second interval. 
    aTimer = new System.Timers.Timer(2000); 
    // Hook up the Elapsed event for the timer. 
    aTimer.Elapsed += OnTimedEvent; 
    aTimer.Enabled = true; 

    Console.WriteLine("Press the Enter key to exit the program... "); 
    Console.ReadLine(); 
    Console.WriteLine("Terminating the application..."); 
16

Ich benutze:

private void WaitNSeconds(int segundos) 
{ 
    if (segundos < 1) return; 
    DateTime _desired = DateTime.Now.AddSeconds(segundos); 
    while (DateTime.Now < _desired) { 
     System.Windows.Forms.Application.DoEvents(); 
    } 
} 
+2

wow erstaunlich, diese Lösung funktioniert perfekt..thank dir :) – aswzen

+1

Ich habe eine Anwendung, die bei .NET 3.5 fest ist (keine async/warten). Das war perfekt. – Locke

+0

Diese Lösung ist effektiv, wenn Sie nicht auf .NET 4.5 aktualisieren können, aber es wird übermäßige CPU-Ressourcen ohne eine geringfügige Optimierung verbrauchen. Siehe meine Antwort für eine detaillierte Erklärung. – Nick

8

Omars Lösung anständig * ist, wenn Sie nicht Ihre Umgebung .NET 4.5, um zu gewinnen, aktualisieren Zugriff auf die asynchronen und abwartenden APIs. Das heißt, hier ist eine wichtige Änderung, die vorgenommen werden sollte, um eine schlechte Leistung zu vermeiden. Zwischen den Aufrufen von Application.DoEvents() sollte eine geringfügige Verzögerung hinzugefügt werden, um übermäßige CPU-Auslastung zu vermeiden. Durch die Zugabe von

Thread.Sleep(1); 

vor dem Aufruf von Application.DoEvents() können Sie eine solche Verzögerung (1 Millisekunde) hinzufügen und die Anwendung verhindern, dass alle CPU-Zyklen zur Verfügung, um es verwenden.

private void WaitNSeconds(int seconds) 
{ 
    if (seconds < 1) return; 
    DateTime _desired = DateTime.Now.AddSeconds(seconds); 
    while (DateTime.Now < _desired) { 
     Thread.Sleep(1); 
     System.Windows.Forms.Application.DoEvents(); 
    } 
} 

* Siehe https://blog.codinghorror.com/is-doevents-evil/ für eine ausführlichere Diskussion über die möglichen Gefahren von Application.DoEvents() verwenden.

+0

Zu der Zeit, als ich diese Lösung veröffentlichte, erfüllte ich nicht die erforderliche Reputation, um Omars Lösung als Kommentar hinzuzufügen. Für jetzt behalte ich diese Antwort offen, da es sich um formatierten Code handelt. – Nick

+1

Ich verwende MVVM-Anwendungen seit Fw 3.5 bis 4.5.1 und sogar mit allen neuen Ressourcen manchmal einfache Lösungen für ein Problem sind die besten – Omar

Verwandte Themen