单击按钮从循环中断 – C#

我有一个关于循环按钮点击事件的问题,我尝试了很多方法并搜索了许多页面以寻找过去一小时的简单答案,但事实是每个答案看起来都像外星人的代码,可能是因为我还是发展的新手。

这是我正在尝试做的简化版本:

private string Message = "Hello"; private void Spam(bool loop) { if(loop == true) { while (loop == true) { MessageBox.Show(Message); } } else { MessageBox.Show("Spamming has stopped !! "); } } private void button1_Click(object sender, EventArgs e) { Spam(true); } private void button2_Click(object sender, EventArgs e) { Spam(false); } 

显然这不是我的API,或者它是一个没用的东西要发明,但是,代码本身很长并且你们总是要求“相关代码”(没有不尊重),所以就是这样。

我的问题:单击按钮2时,打开垃圾邮件循环,我的代码看起来足够让API找出,但每次单击按钮1时,API都会冻结。

使用后台工作人员来完成您的工作。 完成后,您可以使用取消function打破它。 您拥有它的循环将在同步执行时阻止UI线程,这就是您的GUI变得无法响应的原因。 请注意,如果您与do work委托中的UI进行任何交互,则需要封送回UI线程(例如,通过调用)。

 private BackgroundWorker _worker = null; private void goButton_Click(object sender, EventArgs e) { _worker = new BackgroundWorker(); _worker.WorkerSupportsCancellation = true; _worker.DoWork += new DoWorkEventHandler((state, args) => { do { if (_worker.CancellationPending) break; Console.WriteLine("Hello, world"); } while (true); }); _worker.RunWorkerAsync(); goButton.Enabled = false; stopButton.Enabled = true; } private void stopButton_Click(object sender, EventArgs e) { stopButton.Enabled = false; goButton.Enabled = true; _worker.CancelAsync(); } 

要记住一件重要的事情:

在执行代码时,用户无法与您的用户界面进行交互。

这意味着:您首先需要退出循环(即从Spam方法返回), 然后用户可以单击Button2。

这是一个很难的事实,因为这意味着你无法以你想要的方式编写代码。 幸运的是,有几种方法可以解决这个问题:

  • 不要使用循环。 使用某种计时器来做“垃圾邮件”。 Button1启动计时器,Button2停止计时器。 什么样的计时器可用取决于您使用的用户界面库(WinForms有一个Timer ,WPF有一个DispatcherTimer )。

  • 后台线程中进行“垃圾邮件”。 这将允许您的用户界面保持响应,并且您可以与后台线程进行通信,例如,通过设置volatile Boolean 。 但是,这是一个高级主题(并且可能很快导致复杂的同步问题),因此我建议您先尝试其他选项。

单击button1时,将调用Spam方法并启动循环。 当你点击button2时,会调用垃圾邮件方法,但它不一样。 这是第二次执行,因此它将检查条件并且不会进入循环,但第一次调用sill中的循环将运行。

您应该使用一个标志,循环应该使用该标志来确定它是否仍然在运行。 看起来应该是这样的:

 bool run = false; string message = "This API is not original"; private void Spam() { while (run == true) { MessageBox.Show(message); } } } private void button1_Click(object sender, EventArgs e) { message = "Hellooo"; flag = true; Spam(); } private void button2_Click(object sender, EventArgs e) { flag = false; } 

看看这个概念:

 private bool loop = false; private void Start() { loop = true; Spam("Some Message??"); } private void Spam(string message) { while (loop) { MessageBox.Show("This API is not original"); } } private void button1_Click(object sender, EventArgs e) { loop = true; } private void button2_Click(object sender, EventArgs e) { loop = false; } 

但是,如果MessageBox在占用主UI线程时不断弹出,则用户将无法按下按钮。 为了防止这种情况,您可以使用BackgroundWorker或启动新线程。