Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I prevent any button click events from queuing until the event handle is finished with the first call

I want to prevent a button click from queuing. In testing I have a Form, a Button and in the Code-Behind I have the event handler:

    private void button1_Click(object sender, EventArgs e)
    {
        if (_codeRunning)
            return;

        _codeRunning = true;

        //Application.DoEvents();

        //button1.Enabled = false;

        _click ++;

        Debug.WriteLine("Click Number: " + _click);

        Task.Delay(5000).Wait();

        //button1.Enabled = true;

        _codeRunning = false;
    }

When I run debug and click the button twice or three or four times rapidly, Debug Output shows each click about five seconds after the last one. What I would like it to show is a single Click and drop the rest until first Event is complete.

I have also tried to disable the button, as well as temporarily remove the Handler from the Button_click event. It is all the same results.

like image 417
Randy Avatar asked Jun 17 '15 14:06

Randy


People also ask

Which event method is used for button control?

To define the click event handler for a button, add the android:onClick attribute to the <Button> element in your XML layout. The value for this attribute must be the name of the method you want to call in response to a click event.

Is button click an event?

The onclick event executes a certain functionality when a button is clicked. This could be when a user submits a form, when you change certain content on the web page, and other things like that. You place the JavaScript function you want to execute inside the opening tag of the button.


2 Answers

There are various amounts of trouble you'll get into when you hang-up the UI thread like this. This is certainly one of them, nothing pleasant happens when the user wildly bangs on the button to try to get something noticeable to happen. And sure, those clicks won't get lost, they stay stored in the message queue. To activate your Click event handler again when your event handler stops running.

Pretty important to learn how to use the BackgroundWorker or Task classes to avoid this kind of trouble. Just setting the button's Enabled property is then enough to solve this problem.

Purging the mouse clicks from the message queue is technically possible. But ugly to do, it requires pinvoke. I'll hesitantly post the alternative, don't assume that this is in general a good strategy. You'll need to read this post to have some insight into why DoEvents() is a dangerous method.

    private void button1_Click(object sender, EventArgs e) {
        button1.Enabled = false;
        button1.Update();
        '' long running code
        ''...
        Application.DoEvents();
        if (!button1.IsDisposed) button1.Enabled = true;
    }

The Update() call ensures that the user gets the feedback he needs to know that banging the button repeatedly isn't going to do anything useful. The DoEvents() call will dispatch all the queued-up mouse clicks, nothing happens with them since the button is still disabled. The IsDisposed test is essential to solve the problem with DoEvents(), it ensures your program won't crash when the user clicked the window's Close button while the code was running.

Use the HourGlass class in this post to provide more feedback.

like image 143
Hans Passant Avatar answered Sep 24 '22 21:09

Hans Passant


I had a button that on click event was going to run a method. Same issue happent and when the user clicked multiple times the method was triggered multiple times. So I made a boolean and changed it value when the method started.

private bool IsTaskRunning = false;

private void MyMethod()
{
    if ( IsTaskRunning==false )
    {
        IsTaskRunning=true;

        // My heavy duty code that takes a long time

        IsTaskRunning=false; // When method is finished
    }
}

So now the method runs only if it's done the last time.

like image 25
Benjamin Ronneling Avatar answered Sep 22 '22 21:09

Benjamin Ronneling