如何使用按钮停止 for 循环
本文关键字:for 循环 何使用 按钮 | 更新日期: 2023-09-27 18:34:55
我有一个循环,我想停止使用按钮。为更好地理解而编辑:
我确实意识到您无法在循环运行时停止按钮,因为只要当前 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 响应能够取消正在运行的操作,您可以使用 backgrounworker。后台工作者在其他线程中执行工作,同时保持 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()
操作本身,则必须为此提供一种机制。一种可能的方法是使用 CancellationSource
和 CancellationToken
,这提供了一种表达取消语义的便捷方法。
尝试使用 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;