Search code examples
c#.netwinforms.net-4.0

Windows Forms Control.Invoke(Action) blocked while MessageBox is shown?


I have to debug code by a former colleague. The application is part of a machine control. The machine is already delivered to our customer, which restricts my debugging abilities.

The situation is as follows: A Windows Forms MessageBox is shown:

if (MessageBox.Show(toask, "Überprüfung", MessageBoxButtons.OKCancel, MessageBoxIcon.Question, 
                    MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly)
                    != DialogResult.OK)
{
    // Do something here
    return;
}

The user does not click the box away for at least half a minute, because he has to do something, when the box is shown. Meanwhile, I need the callback method of a System.Timers.Timer (500 ms, AutoReset == false) event to be executed:

private void timerLoop_Elapsed(object sender, ElapsedEventArgs e)
{
    Action updateUI = () =>
    {
        // Do some extensive work, accessing Windows Forms controls.
        // I'm expecting a bool variable to be set here.
    }
    if (this.InvokeRequired)
        this.Invoke(updateUI);
    else
        updateUI();

    timerLoop.Start();
}

The bool variable mentioned in the code block is not set, although it should be. Since the callback method is always executed in a thread other than the UI thread, this.Invoke(updateUI) is called (probably could get rid of if(this.InvokeRequired)).

My question is: is the invoked updateUI blocked from executing, while the MessageBox is shown? This would explain the applications behavior. And if so, what can I do to force the callback's execution while MessageBox is shown? Would BeginInvoke() help?

ADDENDUM 1: The timer was formerly a Windows.Forms.Timer instead of a Systems.Timers.Timer. I changed it trying to solve another issue. Before that, the application worked in the situation described above (apart from other issues).

Seems, this info is relevant for the question? However, I don't understand why the Forms.Timer's callback is handled during MessageBox, but not the Control.Invokes in the Timers.Timers callback?


Solution

  • I had the idea to test my theory with a little test application:

    namespace Timers_Test
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
    
                timersTimer.Elapsed += OnElapsed;
    
    
                winFormsTimer.Start();
                timersTimer.Start();
            }
    
            private System.Timers.Timer timersTimer = new System.Timers.Timer(500);
    
    
            private void winFormsTimer_Tick(object sender, EventArgs e)
            {
                tBFormsTimer.Text = DateTime.Now.ToString("hh:mm:ss");
            }
    
            private void OnElapsed(object sender, ElapsedEventArgs e)
            {
                tBTimersTimer.Invoke((Action)(() => tBTimersTimer.Text = DateTime.Now.ToString("hh:mm:ss")));
            }
    
            private void btnMessageBox_Click(object sender, EventArgs e)
            {
                MessageBox.Show("Which Callbacks does this MessageBox block?", "Test", MessageBoxButtons.OK, MessageBoxIcon.Question);
            }
        }
    }
    

    Screenshot of the running application.

    This answers the question: My observation is, that the action in Control.Invoke(Action) is NOT blocked until after clicking away the MessageBox, at least not categorically.