Search code examples
c#event-handlingfocus

Need to click button twice to have an effect


The application is a machine control, so it needs access to ui to show status etc. (I know, goes against the recommendation to separate UI and work code, but it is what it is, at least for now). The issue boils down to this: When one button event handler is not finished, another button needs to be clicked twice. First click gives the focus to the button, next click fires the event.

Here is the issue simplified to extreme. There are two buttons and a label. Stop button needs two clicks to stop the machine:

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";
}

How can I make the button to react to the first click?


Solution

  • DoEvents() is bad. Don't use it.

    If you have to use it (e.g. as workaround), then you are adding technical debt and likely to pay in the future, similar to your case.

    A better approach is to run work inside the task and use cancellation token, but in your case the minimum modification required is this (add async modifier to a method):

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

    The UI should be responsive now.

    The latter is simulating synchronous code, put it instead of Sleep, don't forget to invoke if there you have to modify UI.