开发者

Temporarily disable button

Should be simple, but... :)

I have only one button on the form. The button calls a function, which takes 10 seconds to execute (for example). I would like to temporarily disable the button during this time, so that if the user presses Enter key while the function is executing, nothing would happen.

But now it works this way: user presses Enter and the button becomes disabled. During these 10 seconds the user presses Enter key again and when the first function finishes, it gets called again. I would like to prevent this, so the Enter key would work only when the button gets enabled again. Everything is in the same thread.

My code:

private v开发者_开发百科oid button1_Click(object sender, EventArgs e)
{
    Debug.WriteLine("Click");
    button1.Enabled = false;
    Thread.Sleep(3000); // simulate something...
    button1.Enabled = true;
    button1.Focus();
}

Edit: the function prints something on the printer. Through a printer's API function I can determine when the printing was finished, only then the button can be enabled again.


I had the same problem recently and I decided to post my explanation:

While the lengthy task is executing, the user clicks several times on the button. Windows sends these messages to the application, however the application cannot process them immediately since it is busy at this moment. So the messages wait in a queue for the application to become available. When the application finishes with the task, button's Enabled property is immediately set to True and the next thing happening is, it receives the queued messages. At this moment the button is enabled so the application processes the new clicks as if the button was never disabled.

Fix proposal:

You may insert the line "Application.DoEvents()" just before the line "button1.Enabled = true;" This way the queued messages will reach the button while it is still disabled and the button will now discard them.

Disclaimer: It seems the use of Application.DoEvents() isn't considered a good practice. However it shows nicely what happens in this particular case.

I think that the solution suggested by Rhapsody is better than using Application.DoEvents(). With BackgroundWorker we are creating a second thread and so we do not block the GUI thread. Since the GUI remains responsive, disabling the button will work as expected.


If you know that the operation to execute will take a longer time (e.g. > 5 seconds) it might be better to perform that action asynchronous.

So in that case, take a BackgroundWorker. You can easily disable the button before starting the BackgroundWorker and enable it again in its Completed event.


Try this code.

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();
}

Hope it helps.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜