如何使用按钮停止for循环?

时间:2014-12-22 18:26:19

标签: c# loops button for-loop

我有一个循环,我想停止使用按钮。 编辑以便更好地理解:

我确实意识到在循环运行时你无法停止按钮,因为只要当前的UI正在运行它就无法工作。我真正要求的是创建线程或使用BGWorker来阻止它的最有效方法。我见过一些方法,但大多数方法都是针对Java而不是C#。

我想做的是:

private void start_Click(object sender, EventArgs e)
{

    for(int i = 0; i < nums; i++)
    {
        doSomething();
    }
}

private void stop_Click(object sender, EventArgs e)
{

    stops start_Click()
}

5 个答案:

答案 0 :(得分:7)

你做不到。对于初学者来说,for循环在UI线程上同步运行,这意味着你甚至不能能够点击“停止”按钮。

因此,您需要将for循环的操作移动到另一个线程,这意味着您可能根本不会使用for循环。您需要考虑实际中的代码是如何执行的,然后根据您执行处理的方式,您可以实现“停止”按钮。

一个非常简单的方法就是:

new Thread(() =>
{
   int i = 0;
   while (!stop && i < num)
   {
      doSomething();
      i++;
   }
 }).Start();

并设置stop以停止处理循环。在更现实的情况下,您可以排队要处理的函数,然后通过类似的方法停止出列。不幸的是,很难在不了解更多细节的情况下推荐设置。

任何基于您的代码的解决方案也会遇到当前doSomething()完成执行的问题(可能需要一段时间)。再说一遍,没有更多的信息,很难说最好的解决方法是什么。

答案 1 :(得分:5)

为了让您的UI响应能够取消正在运行的操作,您可以使用背景工作者。 后台工作人员在保持UI响应的同时,在另一个线程中完成工作:

    private readonly BackgroundWorker _backgroundWorker;

    public Form1()
    {
        InitializeComponent();

        _backgroundWorker = new BackgroundWorker
        {
            WorkerSupportsCancellation = true
        };
        _backgroundWorker.DoWork += backgroundWorker_DoWork;
        _backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;

        Disposed += Form1_Disposed;
    }

    private void Form1_Disposed(object sender, EventArgs e)
    {
        _backgroundWorker.Dispose();
    }

    private void StartLoop()
    {
        if ( !_backgroundWorker.IsBusy )
        {
            _backgroundWorker.RunWorkerAsync();
        }
    }

    private void StopLoop()
    {
        _backgroundWorker.CancelAsync();
    }

    private void backgroundWorker_DoWork( object sender , DoWorkEventArgs e )
    {
        var backgroundWorker = ( BackgroundWorker ) sender;

        for ( var i = 0; i < 100; i++ )
        {
            if ( backgroundWorker.CancellationPending )
            {
                e.Cancel = true;
                return;
            }
            // Do Work
        }
    }

    private void backgroundWorker_RunWorkerCompleted( object sender , RunWorkerCompletedEventArgs e )
    {
        if ( e.Cancelled )
        {
            // handle cancellation
        }
        if ( e.Error != null )
        {
            // handle error
        }

        // completed without cancellation or exception
    }

答案 2 :(得分:2)

恕我直言,这里最好的方法是将您的工作转换为异步操作,然后使用async / await成语进行循环。 E.g:

private bool _stopLoop;

private async void start_Click(object sender, EventArgs e)
{
    _stopLoop = false;

    for(int i = 0; i < nums && !_stopLoop; i++)
    {
        await Task.Run(() => doSomething());
    }
}

private void stop_Click(object sender, EventArgs e)
{
    _stopLoop = true;
}

这允许循环本身在管理_stopLoop变量的UI线程中执行,但实际上没有阻塞UI线程(除此之外还会阻止&#34;停止&#34;按钮被点击)。

很遗憾,您没有提供有关doSomething()工作原理的详细信息。可能有一种很好的方法可以将整个方法转换为async方法,但如果没有实际代码,我无法对此进行评论。

请注意,此方法仅在每个操作之间的某个点中断循环。如果您希望能够中断doSomthing()操作本身,那么您必须为此提供一种机制。一种可能的方法是使用CancellationSourceCancellationToken,它提供了表达取消语义的便捷方式。

答案 3 :(得分:0)

尝试使用async / await方法。这很容易!

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

    private CancellationTokenSource _tokenSource;

    private async void start_Click(object sender, EventArgs e)
    {
        if (_tokenSource != null)
            return;

        _tokenSource = new CancellationTokenSource();
        var ct = _tokenSource.Token;

        await Task.Factory.StartNew(() =>
        {
            for (; ; )
            {
                if (ct.IsCancellationRequested)
                    break;
                doSomething();
            }
        }, ct);

        _tokenSource = null;
    }

    private int _labelCounter;

    private void doSomething()
    {
        // do something
        Invoke((Action)(() =>
        {
            myLabel.Text = (++_labelCounter).ToString();
        }));
    }

    private void stop_Click(object sender, EventArgs e)
    {
        if (_tokenSource == null)
            return;

        _tokenSource.Cancel();
    }
}

答案 4 :(得分:-1)

试试这个:

bool stop=false;

private void start_Click(object sender, EventArgs e)
{
for(int i = 0; i < nums&& !bool; i++)
{
doSomething();
}
}

并在点击事件中

设置

stop=true;