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

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

我确实意识到在循环运行时你无法停止按钮,因为只要当前的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() } 

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

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

一个非常简单的方法是:

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

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

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

为了使您的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 } 

恕我直言,这里最好的方法是将你的工作转换为异步操作,然后使用async / await惯用法进行循环。 例如:

 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线程(除此之外还会阻止点击“停止”按钮)。

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

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

尝试使用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(); } } 

试试这个 :

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

并在点击事件中

 stop=true;