2013-08-22 18 views
19

Jestem niewiarygodnie nowy w programowaniu i jak na razie wystarczająco dobrze się uczę, ale nadal nie mogę zrozumieć, jak spóźnić się tak, jak chcę. Nad czym pracuję jest rodzajem "gry" testowej przy użyciu aplikacji formularzy Windows, która obejmuje system walki. W tym chcę stworzyć NPC, który wykonuje akcję co kilka sekund. Problem polega na tym, że chcę również umożliwić graczowi interakcję między atakami. Thread.Sleep naprawdę nie wydają się działać dla mnie nie tylko dlatego, że nie wiem jak Multithread, ale gdy próbuję go uruchomić, powiedzmy tak:Jak mogę wykonać krótkie opóźnienie w C# bez użycia trybu uśpienia?

textBox1.Text += "\r\nThread Sleeps!"; 
System.Threading.Thread.Sleep(4000); 
textBox1.Text += "\r\nThread awakens!"; 

Wydaje nalegają na spanie najpierw, a następnie drukowanie obu linii.

Myślę, że to wszystko, co mogę powiedzieć w tej chwili, ale jeśli to nadal jest zbyt nieprecyzyjne lub rozwlekłe, proszę mi powiedzieć.

Krótko mówiąc, w języku C# Chcę zrobić pewne opóźnienie przed uruchomieniem, ale jednocześnie nadal zezwalam na interakcję użytkownika.

+1

można użyć czasomierza zamiast i ogień go w twoim przedziale ... – Rohit

+0

Wątek jest również odpowiedzialny za drukowanie twojego interfejsu użytkownika, ale ponieważ blokujesz go za pomocą funkcji "Uśpienia", nie może aktualizować interfejsu pokazującego pierwszy wiersz. – user2674389

+0

Użyj Task.Delay zamiast Sleep. Wtedy nie będziesz mieć żadnych problemów z zablokowanym interfejsem użytkownika. Ta nowa funkcja jest dostępna w .Net 4.5. – Ohlin

Odpowiedz

47

Jeśli korzystasz z platformy .NET 4.5, możesz użyć nowej asynchronicznej/oczekującej struktury do uśpienia bez blokowania wątku.

Sposób działania polega na oznaczeniu funkcji wymagającej operacji asynchronicznych za pomocą słowa kluczowego async. To tylko wskazówka dla kompilatora. Następnie należy użyć słowa kluczowego await w wierszu, w którym kod ma być uruchamiany asynchronicznie, a program będzie czekał bez blokowania wątku lub interfejsu użytkownika. Metoda, którą wywołujesz (w linii oczekującej) musi być również oznaczona słowem kluczowym async i zwykle nosi nazwę kończącą się na Async, tak jak w przypadku ImportFilesAsync.

Co trzeba zrobić w przykładzie jest:

  1. Upewnij się, że program ma .Net Framework 4.5 jak docelowy ram
  2. Mark czynność, która musi spać z kluczowych async (patrz przykład poniżej)
  3. Dodaj using System.Threading.Tasks; do swojego kodu.

Twój kod jest już gotowy do użycia metody zamiast metody System.Threading.Thread.SleepTask.Delay (możliwe jest użycie await na Task.Delay ponieważ Task.Delay oznaczona async w jej definicji).

private async void button1_Click(object sender, EventArgs e) 
    { 
     textBox1.Text += "\r\nThread Sleeps!"; 
     await Task.Delay(3000); 
     textBox1.Text += "\r\nThread awakens!"; 
    } 

Tutaj można przeczytać więcej na temat Task.Delay i Await.

+0

Czy to prawda, że ​​cały kod po "Oczekiwanie" będzie działał asynchronicznie? Zrobiłem przykład z dwoma polami wyboru i wydaje się, że tak jest. – Black

+0

@ Black Możesz tylko użyć 'await' na funkcji, która jest oznaczona jako' async', więc tak - zawsze będzie asynchroniczna. – Ohlin

+0

, ale tylko część po oczekiwaniu? – Black

4

Przepraszamy za przebudzenie starego pytania w ten sposób. Ale myślę, że oryginalny autor chciał, jako odpowiedź:

Musisz wymusić swój program, aby dokonać aktualizacji graficznej po wprowadzeniu zmiany w polu tekstowym1.Można to zrobić poprzez wywołanie Update();

textBox1.Text += "\r\nThread Sleeps!"; 
textBox1.Update(); 
System.Threading.Thread.Sleep(4000); 
textBox1.Text += "\r\nThread awakens!"; 
textBox1.Update(); 

Normalnie Będzie się to odbywać automatycznie, gdy wątek jest wykonywana. Naciśnięcie przycisku, zmiany w tekście, matryce wątków, a następnie .Update() zostaje uruchomiony i widać zmiany. (Nie jestem ekspertem, więc naprawdę nie mogę powiedzieć, kiedy zostałeś zwolniony, ale jest to coś podobnego do tego w dowolny sposób.)

W takim przypadku wprowadzasz zmianę, wstrzymujesz wątek, a następnie zmieniasz tekst ponownie, i kiedy wątek w końcu zginie .Update() jest strzelany. Powoduje to, że widzisz tylko ostatnią zmianę wprowadzoną w tekście.

Wystąpiłby ten sam problem, gdyby długa egzekucja między zmianami tekstu.

0
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(); 
    } 
} 
0

Dodając using System.Timers; do programu można użyć tej funkcji:

private static void delay(int Time_delay) 
{ 
    int i=0; 
    // ameTir = new System.Timers.Timer(); 
    _delayTimer = new System.Timers.Timer(); 
    _delayTimer.Interval = Time_delay; 
    _delayTimer.AutoReset = false; //so that it only calls the method once 
    _delayTimer.Elapsed += (s, args) => i = 1; 
    _delayTimer.Start(); 
    while (i == 0) { }; 
} 

opóźnienie jest funkcją i może być używany jak:

delay(5000); 
Powiązane problemy