Dot NET
Dot NET

Reputation: 4897

Strange issue when disabling a button

I've got a WinForm, which contains a button. In the button's click event, I call button1.Enabled = false and then a number of lines of code follow. After this code, I call button1.Enabled = true.

This is done so that the button cannot be pressed while the execution is being carried out. The strange thing is that while the button is disabled, if the user clicks on the button many times, the button is actually clicked.

Could anyone explain why this is happening? The code looks like this:

button1.Enabled = false
//Code
//Code
//Code
button1.Enabled = true

Upvotes: 2

Views: 2189

Answers (3)

Nathaniel
Nathaniel

Reputation: 21

I solved this using Application.DoEvents() to empty the queue before re enabling the button

    AppButton.Enabled = false;
    ...
    do some work
    ...
    Application.DoEvents();
    AppButton.Enable = true;

Upvotes: 2

Jon Skeet
Jon Skeet

Reputation: 1500375

My guess is that you're actually doing a load of work in those lines of code, blocking the UI thread. You shouldn't do that - you should set the button to be disabled, then start off your work in a background thread (or using asynchronous calls, if most of the time is spent talking to a web service or something similar). Then when the work is finished, it should marshal a call back into the UI thread to re-enable the button.

(If that's not the problem, please show a short but complete program which demonstrates the problem.)

EDIT: Thanks to Sarwar's comments, I understand why you're getting the multiple events being fired - they're being queued up (due to the UI thread being blocked), and only processed after the button is re-enabled. So yes, if you avoid doing lots of work on the UI thread, it can handle the clicks on the disabled button, ignore them, and then there won't be a backlog when the button is re-enabled.

EDIT: For anyone who is interested in trying this themselves, here's my test program demonstrating the problem:

using System;
using System.Windows.Forms;
using System.Threading;
using System.Threading.Tasks; // For the fix below

class Program
{
    static void Main()
    {
        Button button = new Button { Text = "Click me" };
        button.Click += HandleClick;
        Form form = new Form { Controls = { button } };
        Application.Run(form);
    }

    static void HandleClick(object sender, EventArgs e)
    {
        Console.WriteLine("In click handler");
        Button button = (Button) sender;
        button.Enabled = false;
        Thread.Sleep(10000);
        button.Enabled = true;        
        Console.WriteLine("Finishing click handler");
    }
}

And the fix using C# 5's async handling:

static async void HandleClick(object sender, EventArgs e)
{
    Console.WriteLine("In click handler");
    Button button = (Button) sender;
    button.Enabled = false;
    // Delay by 10 seconds, but without blocking the UI thread
    await TaskEx.Delay(10000);
    button.Enabled = true;        
    Console.WriteLine("Finishing click handler");
}

Upvotes: 5

Mikael Koskinen
Mikael Koskinen

Reputation: 12906

We encountered this same problem and like Jon mentioned, it was because the UI was blocked by the work we did inside the click event. When the UI resumed, it registered all the clicks which had happened when the UI was blocked.

Here's an another answer from Stack Overflow which provides some code showing how you can fix the problem.

Upvotes: 1

Related Questions