2014-12-20 18 views
8

Mam pytanie dotyczące zapętlenia z kliknięciem przycisku Zdarzenie, próbowałem wielu metod. & przeszukałem wiele stron w poszukiwaniu prostej odpowiedzi na ostatnią godzinę, ale prawda jest każdą odpowiedzią po prostu wygląda jak obcy kod, prawdopodobnie dlatego, że wciąż jestem nowy w rozwoju.Przerywanie z pętli za pomocą kliknięcia przycisku - C#

Oto uproszczona wersja tego, co próbuję zrobić:

private string Message = "Hello"; 

private void Spam(bool loop) 
    { 
    if(loop == true) 
    { 
     while (loop == true) 
     { 
     MessageBox.Show(Message); 
     } 
    } else { MessageBox.Show("Spamming has stopped !! "); } 
    } 

private void button1_Click(object sender, EventArgs e) 
     { 
      Spam(true); 
     } 
private void button2_Click(object sender, EventArgs e) 
     { 
      Spam(false); 
     } 

Oczywiście nie jest to mój API, lub byłoby bezużyteczne rzeczy wymyślić, jednak sam kod jest długa & chłopaki zawsze pytają o "odpowiedni kod" (brak szacunku), więc tak jest.

Mój problem: Wyłamując się z pętli spamu po kliknięciu przycisku 2, kod dla mnie wygląda na dość przyzwoity, aby API mógł to zrozumieć, ale za każdym razem, gdy kliknięto przycisk 1, API zawiesił się.

+0

Nie jest to możliwe w przypadku pojedynczego wątku. Można to zrobić, jeśli używasz co najmniej dwóch wątków - jednego, który wykonuje zadanie w tle ("pętla"), i drugiego, które przetwarza zdarzenia kliknięcia użytkownika, I zasoby współużytkowane przez te dwa wątki (jak, 'static bool' dla C#) – Lanorkin

+0

nie musisz wywoływać Spamu (Hi, false) w drugim przycisku, łatwo zdefiniować globalną zmienną zwaną w BreakLoop domyślnie = false, a kiedy klikniesz pierwszy przycisk, zmień jego wartość na false, a Ty podczas pętli sprawdź czy ta zmienna jest nadal prawdziwa, a następnie kontynuuj, a kiedy klikniesz drugi przycisk, ustaw tę zmienną na wartość true, przez co przerwiesz pętlę – Monah

+0

Wy, ludzie zachowujący się tak, jakbyś nie mówił Alien? czy robisz to celowo? -_-. x – Hellooo123

Odpowiedz

9

Użyj pracownika w tle, aby wykonać swoją pracę. Możesz skorzystać z funkcji anulowania, aby wyrwać się z niej, gdy skończysz. Twoja pętla, jak to masz, zablokuje wątek interfejsu użytkownika po wykonaniu synchronicznie, dlatego twój interfejs GUI przestaje odpowiadać. Uwaga: jeśli wykonujesz jakąkolwiek interakcję z interfejsem użytkownika w delegacie do pracy, musisz powrócić do wątku UI (na przykład przez wywołanie).

private BackgroundWorker _worker = null; 

private void goButton_Click(object sender, EventArgs e) 
{ 
    _worker = new BackgroundWorker(); 
    _worker.WorkerSupportsCancellation = true; 

    _worker.DoWork += new DoWorkEventHandler((state, args) => 
    { 
     do 
     { 
      if (_worker.CancellationPending)     
       break; 

      Console.WriteLine("Hello, world"); 

     } while (true); 
    }); 

    _worker.RunWorkerAsync(); 
    goButton.Enabled = false; 
    stopButton.Enabled = true; 
} 

private void stopButton_Click(object sender, EventArgs e) 
{ 
    stopButton.Enabled = false; 
    goButton.Enabled = true; 
    _worker.CancelAsync(); 
} 
+0

Doskonała odpowiedź i świetne wprowadzenie do pracowników z zaplecza. Zrobiłeś mój dzień, miła robota. – Hellooo123

+0

Ktoś wie, jak przekazać anonimowy obiekt o RunWorkerAsync()? coś podobnego do backgroundWorker1.RunWorkerAsync (new {start = 108, end = 502404}); – boctulus

+1

@Boctulus, jak to powinno być w porządku ... w metodzie 'DoWork' powinna pojawić się w parametrze' DoWorkEventArgs' ('args' w powyższym przykładzie). Następnie możesz po prostu użyć swojego obiektu po uzyskaniu takiego odnośnika, 'dynamic anon = args.Argument;'. – steve16351

0

Spójrz na tej koncepcji:

private bool loop = false; 

private void Start() 
{ 
    loop = true; 
    Spam("Some Message??"); 
} 

private void Spam(string message) 
{ 
    while (loop) 
    { 
     MessageBox.Show("This API is not original"); 
    } 
} 

private void button1_Click(object sender, EventArgs e) 
{ 
    loop = true; 
} 

private void button2_Click(object sender, EventArgs e) 
{ 
    loop = false; 
} 

Jednak użytkownik nie będzie mógł nacisnąć przycisk, gdy MessageBox utrzymuje pojawiały się jak to ma się do głównego wątku UI. Aby temu zapobiec, możesz użyć BackgroundWorker lub rozpocząć nowy wątek.

+0

Zmieniono MessageBox na label1.Text, zawiesza się, a (loop) ma zawsze wartość true, nie ma szans na kliknięcie przycisku 2 click – Hellooo123

+4

Dlaczego uważasz, że ten kod nie zablokuje interfejsu użytkownika? –

6

Jest jeszcze jedna ważna rzecz do zapamiętania:

Podczas gdy kod jest wykonywany, użytkownik nie może wchodzić w interakcje z interfejsem użytkownika.

To oznacza, najpierw trzeba wyjściu pętli (tj powrotnej sposobu Spam) i następnie użytkownik może kliknąć Button2.

To trudna prawda, ponieważ oznacza, że ​​nie możesz napisać kodu w sposób, w jaki chciałeś. Na szczęście istnieje kilka sposobów obejścia tego:

  • Nie używaj pętli. Użyj jakiegoś rodzaju timera, aby wykonać "spamowanie". Przycisk 1 uruchamia timer, przycisk 2 zatrzymuje go. Rodzaj zegara jest dostępny w zależności od używanej biblioteki interfejsu użytkownika (WinForm ma numer Timer, WPF ma numer DispatcherTimer).

  • Wykonaj "spamowanie" w wątku tła . Dzięki temu interfejs użytkownika pozostanie responsywny, a użytkownik będzie mógł komunikować się z wątkiem tła, na przykład ustawiając volatile Boolean. Jest to jednak zaawansowany temat (i może szybko doprowadzić do złożonych problemów z synchronizacją), więc sugeruję, aby najpierw wypróbować drugą opcję.

+0

Widziałem wątki używane w kilku API, z którymi ostatnio zacząłem pracować, więc zdecydowanie powinienem się na tym skupić, dziękuję za te heads up, bardzo użyteczne. – Hellooo123

0

Po kliknięciu przycisku 1 wywoływana jest metoda Spam i uruchamiana jest pętla. Po kliknięciu przycisku 2 wywoływana jest metoda Spam, ale to nie to samo. Jest to drugie wykonanie, więc sprawdzi stan i nie wejdzie w pętlę, ale pętla w pierwszym parapecie wywołania będzie działać.

Należy użyć flagi, a pętla powinna użyć tej flagi, aby określić, czy powinna ona nadal działać.Powinno to wyglądać mniej więcej:

bool run = false; 

string message = "This API is not original"; 

private void Spam() 
    { 
     while (run == true) 
     { 
     MessageBox.Show(message); 
     } 
    } 
    } 

private void button1_Click(object sender, EventArgs e) 
     { 
      message = "Hellooo"; 
      flag = true; 
      Spam(); 
     } 
private void button2_Click(object sender, EventArgs e) 
     { 
      flag = false; 
     } 
Powiązane problemy