应该很简单,但......:)
表单上只有一个按钮。该按钮调用一个函数,该函数需要10秒才能执行(例如)。我希望在此期间暂时禁用该按钮,这样如果用户在执行该功能时按下Enter键,则不会发生任何事情。
但现在它以这种方式工作:用户按Enter键,按钮变为禁用状态。在这10秒钟内,用户再次按下Enter键,当第一个功能完成时,再次调用它。我想阻止这一点,所以只有当按钮再次启用时,Enter键才会起作用。一切都在同一个线程中。
我的代码:
private void button1_Click(object sender, EventArgs e)
{
Debug.WriteLine("Click");
button1.Enabled = false;
Thread.Sleep(3000); // simulate something...
button1.Enabled = true;
button1.Focus();
}
编辑:该功能在打印机上打印一些东西。通过打印机的API功能,我可以确定打印完成的时间,然后才能再次启用该按钮。
答案 0 :(得分:4)
我最近遇到了同样的问题,我决定发布我的解释:
当执行冗长的任务时,用户会在按钮上多次单击。 Windows将这些消息发送到应用程序,但是应用程序无法立即处理它们,因为此时它正忙。因此消息在队列中等待应用程序变为可用。当应用程序完成任务时,按钮的Enabled属性立即设置为True,接下来发生的事情是,它接收排队的消息。此时按钮已启用,因此应用程序会处理新的点击,就像按钮从未被禁用一样。
修正提案:
您可以在“button1.Enabled = true;”行之前插入“Application.DoEvents()”行这样排队的消息将在按钮仍处于禁用状态时到达按钮,按钮现在将丢弃它们。
免责声明:似乎使用Application.DoEvents()并不是一种好习惯。然而,它很好地展示了在这种特殊情况下会发生什么。
我认为Rhapsody建议的解决方案比使用Application.DoEvents()更好。使用BackgroundWorker,我们正在创建第二个线程,因此我们不会阻止GUI线程。由于GUI保持响应,因此禁用该按钮将按预期工作。
答案 1 :(得分:1)
如果您知道要执行的操作需要更长的时间(例如> 5秒),那么异步执行该操作可能会更好。
因此,在这种情况下,请BackgroundWorker。您可以在启动BackgroundWorker之前轻松禁用该按钮,并在其已完成事件中再次启用它。
答案 2 :(得分:0)
试试这段代码。
AutoResetEvent _autoResetEvent = new AutoResetEvent(false);
private button1_click(object o, EventArgs e)
{
button1.Enabled = false;
DoPrinterJob();
button1.Enabled = _autoResetEvent.WaitOne();
}
private void DoPrinterJob()
{
//Do something.
_autoResetEvent.Set();
}
希望它有所帮助。