Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Breaking from a loop with button click - C#

Tags:

c#

loops

button

I have a question regarding looping with button click event, I've tried many methods & searched many pages in search for a simple answer for the past hour, but the truth is each answer just looks like alien code, probably because I'm still very new to developing.

Here's a simplified version of what I'm trying to do :

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

Obviously this isn't my API, or it'd be a useless thing to invent, however, the code itself is long & you guys always ask for "relevant code" (No disrespect), so there it is.

My problem : Breaking out of the spam loop upon clicking button 2, the code to me looks decent enough for the API to figure out, but each time button 1 is clicked, the API freezes.

like image 673
Hellooo123 Avatar asked Dec 20 '14 12:12

Hellooo123


1 Answers

Use a background worker to do your work. You can use the cancellation feature to break out of it when you're done. Your loop as you have it will block the UI thread when executed syncronously, which is why your GUI becomes unresponsive. Note if you do any interaction with the UI in the do work delegate, you need to marshal back onto the UI thread (via invoke for example).

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

Update 2019: BackgroundWorker is now largely obsolete, replaced by the async/await feature in later versions of C# which is easier to use. Here is an example of how to achieve the same thing using that feature:

private CancellationTokenSource _canceller;

private async void goButton_Click(object sender, EventArgs e)
{
    goButton.Enabled = false;
    stopButton.Enabled = true;

    _canceller = new CancellationTokenSource();
    await Task.Run(() =>
    {
        do
        {
            Console.WriteLine("Hello, world");
            if (_canceller.Token.IsCancellationRequested)
                break;

        } while (true);
    });

    _canceller.Dispose();
    goButton.Enabled = true;
    stopButton.Enabled = false;
}

private void stopButton_Click(object sender, EventArgs e)
{
    _canceller.Cancel();
}
like image 147
steve16351 Avatar answered Sep 27 '22 21:09

steve16351