需要点击两次按钮才能产生效果



应用程序是一个机器控件,因此它需要访问ui来显示状态等。问题归结为:当一个按钮事件处理程序没有完成时,另一个按钮需要单击两次。第一次单击将焦点放在按钮上,下一次单击将触发事件。

这是一个简化到极端的问题。有两个按钮和一个标签。停止按钮需要点击两次才能停止机器:

bool Stop = true;
private void Start_button_Click(object sender, EventArgs e)
{
RunMachine();
}
private void Stop_button_Click(object sender, EventArgs e)
{
Stop = true;
}
private void RunMachine()
{
Stop = false;
Status_label.Text = "Running";
do
{
Application.DoEvents();
Thread.Sleep(50);
} 
while (!Stop);
Status_label.Text = "Stopped";
}

如何使按钮对第一次点击做出反应?

DoEvents((不正确。不要用它。

如果你必须使用它(例如作为变通方法(,那么你就增加了技术债务,并且很可能在未来偿还,这与你的情况类似。

更好的方法是在任务内部运行工作并使用取消令牌,但在您的情况下,所需的最小修改是这样的(向方法添加异步修饰符(:

while (!Stop)
{
await Task.Delay(50);
// or
await Task.Run(() => Thread.Sleep(50));
}

UI现在应该可以响应了。

后者是模拟同步代码,将其放在Sleep中,如果必须修改UI,请不要忘记调用。

谢谢!我没有意识到Doevents的含义,使用async和await也同样简单。我添加了一个计数器,向自己表明玩具示例正在做我认为的事情。为了使答案完整,并帮助像我这样可能搜索同一问题答案的其他人,这里又是完整的示例。这可以按需工作(只需单击即可停止(,并且如果关闭主窗体而不单击停止,则不会使RunMachine((继续运行。(我的实际应用程序在表单关闭事件中有足够的代码来防止这种情况发生,但我肯定没有意识到这个陷阱。(

bool Stop = true;
private async void Start_button_Click(object sender, EventArgs e)
{
await RunMachine();
}
private void Stop_button_Click(object sender, EventArgs e)
{
Stop = true;
}
internal async Task RunMachine()
{
Status_label.Text = "started";
Stop = false;
int i=0;
do
{
await Task.Delay(500);
Status_label.Text = i.ToString();
i++;
} while (!Stop);
Status_label.Text = "Stopped";
}

最新更新