【问题标题】:C# Form Application - Stop an ongoing process with a click of another buttonC# 表单应用程序 - 通过单击另一个按钮停止正在进行的进程
【发布时间】:2020-04-08 14:18:48
【问题描述】:

是否可以通过在 Windows 窗体应用程序中单击按钮来停止正在进行的进程?

  1. 例如,假设有 2 个按钮,“开始”和“停止”
  2. 当您按下“开始”时,它将开始一个无限循环,打印从 1 到无穷大的数字。
  3. 当我按“STOP”时,该过程应该在那个时刻停止。
  4. 但问题是,我不能按“停止”按钮,因为它不允许我,因为有一个正在进行的过程。

有没有办法克服这个问题?

我知道有一个叫做“MethodInvoker”的东西,但我不知道它是如何工作的,也不知道它是否与此相关。

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

【问题讨论】:

  • 显示代码总是有帮助的,否则我们只会猜测您的程序发生了什么。
  • 我的代码有点长,但我会创建一个较短的版本并上传
  • 嗨。你还在吗?任何解决方案对您有帮助吗?
  • Oguz Ozgul - 你的解决方案对我有用。不过有一个小问题。当我尝试将文本放在标签上时,它给了我一个例外。但这只是一个测试应用程序,所以感谢你我找到了解决方案

标签: c# .net


【解决方案1】:

编辑 1:

如果您需要与 UI 控件交互,从后台任务执行此操作会引发无效操作 -> 非法跨线程异常。为了克服这个问题,

查看Control.InvokeRequired

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

您可以通过提供 CancellationToken 来启动Task,并在单击停止按钮时取消操作。

该任务将在另一个线程上执行无限循环,您的主线程(UI 线程)不应该受到影响并且应该可以访问。

试试这个:

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


}

【讨论】:

  • 这行得通,谢谢 Oguz Ozgul。虽然遇到了一个小问题,无法向标签添加文本,给出异常 - “跨线程操作无效”......但由于这是一个测试应用程序,我不需要那部分
  • 当然,如果您正在操作 UI 控件,您需要在 UI 线程上运行操作操作。我现在正在将如何做到这一点添加到我的解决方案中。
  • 完美的家伙? 没有任何问题 ? 非常感谢
【解决方案2】:

如果你产生了一个新进程,那么你可以调用 kill 方法。

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

如果你已经启动了新线程,那么调用 abort 方法来停止线程。

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

【讨论】:

  • 在其他进程运行时,我什至无法按下按钮。那么,有什么解决方法吗?
  • 因为您的 UI 线程忙于更新 MesgeLabel.Text 和 Thread.Sleep()。 Thread.Sleep() 不会释放 UI 线程。
  • 是的,这就是我需要解决方案的问题。我知道这没问题,但我有点想在进程进行时访问我的用户界面
【解决方案3】:

当您按下“开始”按钮时,运行和打印数字的代码将在 ui 线程上运行。 (根据您的解释,我假设您所拥有的只是按钮按下事件的消息处理程序,没有别的。例如:不设置单独的线程。)。

在 ui 线程上运行无限循环意味着您没有更多时间来处理其他消息。 (负责处理 ui 消息的线程卡在无限循环中。)

因此,为了能够按下“停止”按钮,您需要在不同的线程或完全不同的进程中运行具有无限循环的代码。这就是 Arjun 想要告诉你的。 (如果您希望无限循环中的代码访问表单应用程序中的资源,则需要一个线程。[线程在表单应用程序进程内。])

请注意:如果您创建一个线程并在该线程内运行您的数字打印代码,这将不是 ui 线程。因此,您将无法像在 ui 线程上一样与表单控件进行交互。 (即:尝试设置 windows.text 以显示您的数字很可能会引发异常。)

【讨论】:

  • 感谢您的解释? 我会尝试不同的选择。目前 Oguz Ozgul 的解决方案对我有用
猜你喜欢
  • 1970-01-01
  • 2019-11-07
  • 1970-01-01
  • 2013-02-20
  • 2011-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多