简体   繁体   中英

C# Form Application - Stop an ongoing process with a click of another button

Is it possible to stop an ongoing process with a button click in Windows form application?

  1. For example, let's say there are 2 buttons, "START" and "STOP"
  2. When you press "START", it will start an infinite loop, printing numbers from 1 to infinity.
  3. When I press "STOP", the process should stop at that moment.
  4. But the problem is, I cannot press the "STOP" button as it does not allow me, since there's an ongoing process.

Is there a way to overcome this?

I know there's something called "MethodInvoker", but I have no idea how that works or whether it is relevant to this.

    private bool keepRunning = true;

    public Form1()
    {
        InitializeComponent();
    }

    private void StartBtn_Click(object sender, EventArgs e)
    {
        var number = 1;
        while (keepRunning)
        {
            Thread.Sleep(1000);
            MesgeLabel.Text = "" + number++;
        }
    }

    private void StopBtn_Click(object sender, EventArgs e)
    {
        //Cannot even click this button
        keepRunning = false;
        //or
        Application.Exit();
    }

If you have spawned a new process then you can call kill method.

Process myProcess = Process.Start("Notepad.exe")//starts new process
myProcess.Kill();// kills the process. save reference to myProcess and call kill on STOP button click

If you have started new thread then call abort method to stop the thread.

Thread thread = new Thread(new ThreadStart(method)); 
thread.Start(); 
thread.Abort(); // terminates the thread. call abort on STOP button click

When you press the "start" button, the code that runs and prints the numbers will run on the ui thread. (from your explanation, i assume that all you have is the message handler for the button press event and nothing else. eg: Not setting up a seperate thread.).

Running an infinite loop on the ui thread means, that you do not get any more time for processing other messages. (the thread that is responsible for processing the ui messages is stuck in your infinite loop.)

So, in order to be able to press the "stop" button, you need to run the code with the infinite loop in a different thread or in a different process altogether. This is what Arjun is trying to tell you. (if you want the code in the infinite loop to access resources from your form app, you need a thread. [the thread is inside the forms app process.])

please note: if you create a thread and run your number printing code inside that thread, this will not be the ui thread. Thus, you will not be able to interact with the forms controls as if you'd be on the ui thread. (ie: trying to set the windows.text in order to display your numbers will most likely throw an exception.)

EDIT 1:

If you need to interact with UI controls, doing it from a background task would throw invalid operation -> illegal cross thread exception. To overcome this,

check Control.InvokeRequired

if(myLabel.InvokeRequired)
    myLabel.Invoke(new Action(() => myLabel.Text = newText));
else
    myLabel.Text = newText;

You can start a Task by providing a CancellationToken and cancel the operation when the stop button is clicked.

The task will execute the infinite loop on another thread and your main thread (the UI thread) should not be affected and should be accessible.

Try this:

/*
    Please add these on top of your form class

    using System.Diagnostics;
    using System.Threading;
    using System.Threading.Tasks;
*/

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    CancellationTokenSource cancellationTokenSource;
    CancellationToken cancellationToken;

    private void CountToInfinity()
    {
        while (true)
        {
            cancellationToken.ThrowIfCancellationRequested();

            Debug.WriteLine(new Random().Next());
        }
    }

    private async void button1_Click(object sender, EventArgs e)
    {
        if (cancellationTokenSource == null)
        {
            cancellationTokenSource = new CancellationTokenSource();
            cancellationToken = cancellationTokenSource.Token;
            Task.Run((Action)CountToInfinity, cancellationToken);
        }
    }

    private void button2_Click(object sender, EventArgs e)
    {
        if (cancellationTokenSource != null)
        {
            cancellationTokenSource.Cancel();
            cancellationTokenSource.Dispose();
            cancellationTokenSource = null;
        }
    }


}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM