2014-12-20 2 views
8

У меня есть вопрос относительно цикла с нажатием кнопки, я пробовал много методов. & искал много страниц в поисках простого ответа за последний час, но правда каждый ответ просто выглядит как чужой код, вероятно, потому, что я все еще очень новичок в разработке.Ломается от цикла с нажатием кнопки - C#

Вот упрощенная версия того, что я пытаюсь сделать:

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

Очевидно, что это не мой API, или это было бы бесполезно, что нужно придумать, однако, сам код длиной & вы, ребята, всегда просите «соответствующий код» (нет неуважения), так что это так.

Моя проблема: если вы отключаете спам-контур при нажатии кнопки 2, код для меня выглядит достаточно приличным для API, но каждый раз, когда нажимается кнопка 1, API замерзает.

+0

Невозможно с одной резьбой. Это можно сделать, если вы используете по крайней мере два потока - один, который выполняет фоновые задания («цикл»), и другой, который обрабатывает события щелчка пользователя, и ресурс, разделяемый между этими двумя потоками (например, 'static bool' для C#) – Lanorkin

+0

вам не нужно вызывать спам (Hi, false) во второй кнопке, легко определить глобальную переменную, вызываемую в BreakLoop по умолчанию = false, и когда вы нажимаете первую кнопку, измените ее значение на false и в вас, пока цикл проверяет, если эта переменная по-прежнему верна, а затем продолжает, и когда вы нажимаете вторую кнопку, поверните эту переменную в true, этим вы сломаете петлю – Monah

+0

Вы, ребята, действуете так, как будто вы не говорите Иностранец? или делать это намеренно? -_-. x – Hellooo123

ответ

9

Используйте фона рабочего, чтобы выполнить свою работу. Вы можете использовать функцию отмены, чтобы выйти из нее, когда закончите. Ваша петля, как у вас, будет блокировать поток пользовательского интерфейса при выполнении синхронно, поэтому ваш графический интерфейс становится невосприимчивым. Обратите внимание, что если вы выполняете какое-либо взаимодействие с пользовательским интерфейсом в делете делегирования работы, вам необходимо перевести обратно в поток пользовательского интерфейса (например, с помощью вызова).

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

Отличный ответ и отличное введение в работу на заднем плане. Ты сделал мой день, хорошая работа. – Hellooo123

+0

Кто-нибудь знает, как передать анонимный объект o RunWorkerAsync()? что-то вроде backgroundWorker1.RunWorkerAsync (new {start = 108, end = 502404}); – boctulus

+1

@Boctulus, так как у вас это должно быть хорошо .. в методе DoWork, он должен отображаться в параметре DoWorkEventArgs ('args' в примере выше). Затем вы можете просто использовать свой объект после получения такой ссылки: 'dynamic anon = args.Argument;'. – steve16351

0

Взгляните на эту концепцию:

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; 
} 

Однако пользователь не сможет нажать на кнопку, если MessageBox продолжает выскакивать, как это занимает основной поток пользовательского интерфейса. Чтобы предотвратить это, вы можете использовать BackgroundWorker или запустить новый поток.

+0

Изменено MessageBox на label1.Text, зависает, while (цикл) всегда правдиво, нет шансов для кнопки 2 click event – Hellooo123

+4

Почему, по вашему мнению, этот код не затормозит пользовательский интерфейс? –

6

Там одна важная вещь, чтобы помнить:

Хотя ваш код выполняется, пользователь не может взаимодействовать с пользовательским интерфейсом.

Это означает, что: Сначала необходимо выхода петля (т.е. возврата из метода Spam), а затем пользователь может щелкнуть Button2.

Это трудная истина, потому что это означает, что вы не можете написать код так, как вы хотели. К счастью, есть несколько способов обойти это:

  • Не используйте петлю. Используйте какой-то таймер, чтобы сделать «спам». Button1 запускает таймер, Button2 останавливает его. Какой тип таймера доступен, зависит от используемой библиотеки пользовательского интерфейса (WinForms имеет Timer, WPF имеет DispatcherTimer).

  • Сделайте «спам» в фоновом режиме . Это позволит вашему пользовательскому интерфейсу оставаться отзывчивым, и вы можете общаться с фоновым потоком, например, установив volatile Boolean. Это, однако, расширенная тема (и может быстро привести к сложным проблемам синхронизации), поэтому я предлагаю сначала попробовать другой вариант.

+0

Я видел фоновые потоки, используемые в нескольких API, с которыми я недавно начал работать, поэтому я определенно должен сосредоточиться на этом, спасибо за это хедз-ап, очень полезно – Hellooo123

0

При нажатии кнопки1 вызывается метод спама и начинается цикл. Когда вы нажимаете кнопку2, вызывается метод спама, но это не то же самое. Это второе исполнение, поэтому оно проверит условие и не войдет в цикл, но цикл на первом подоконнике будет запущен.

Вы должны использовать флаг, и цикл должен использовать этот флаг, чтобы определить, должен ли он все еще работать.Он должен выглядеть примерно так:

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; 
     } 
Смежные вопросы