Friday 17 July 2020

Can a form tell if there are any modal windows open?

How, being inside the main form of my WinForm app can I tell if there are any modal windows/dialogs open that belong to the main form?


Answers:


Long story short: opening a modal form is blocks execution on the main form as long as the modal window is open, so your main form can never check to see if its opened any modal forms until after the modal form has closed. In other words, your question is based on a misunderstanding of how modal forms work, so its moot altogether.

For what its worth, it is possible to tell if there are any modal forms open:

foreach (Form f in Application.OpenForms)
{
    if (f.Modal)
    {
        // do stuff
    }
}

Answers:


if (this.Visible && !this.CanFocus)
{
    // modal child windows are open
}

Answers:


You maybe can use the events for EnterThreadModal and LeaveThreadModal. Here is an example how you can do it:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            Application.EnterThreadModal += new EventHandler(Application_EnterThreadModal);
            Application.LeaveThreadModal += new EventHandler(Application_LeaveThreadModal);

            Application.Run(new Form1());
        }

        private static void Application_EnterThreadModal(object sender, EventArgs e)
        {
            IsModalDialogOpen = true;
        }

        private static void Application_LeaveThreadModal(object sender, EventArgs e)
        {
            IsModalDialogOpen = false;
        }

        public static bool IsModalDialogOpen { get; private set; }
    }
}

Answers:


Timers still run and fire events.
Example that works...

public partial class Form1 : Form
{
    Form2 f2 = new Form2();
    public Form1()
    {
        InitializeComponent();
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
        f2.UpdateData(DateTime.Now.ToString());
        if (!f2.Visible) f2.ShowDialog();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        f2.ShowDialog();
        MessageBox.Show('Done');
    }
}

Answers:


If you Google a bit you will find that Form.ShowDialog() disables other forms to prevent user input to those forms of the current one. But most everything else (like timers and other events from sources external to the displayed form) continues to run.


Answers:


This is an illustration why this answer is correct and the assumptions made in this answer are sometimes wrong.

if (MyForm.CanFocus == false && MyForm.Visible == true)
{
    // we are modal            
}

This works for modal shown sub Forms and for MessageBoxes.


Some demo code:

private void modalTest_Click(object sender, EventArgs e)
{
    // Timer which fires 100ms after the first message box is shown
    System.Windows.Forms.Timer canFocusTimer = new System.Windows.Forms.Timer();
    canFocusTimer.Tick += CanFocusTimer_Tick;
    canFocusTimer.Interval = 100;
    canFocusTimer.Start();
    
    // First MessageBox shows that CanFocus == true
    MessageBox.Show($"First MessageBox: { nameof(this.CanFocus) } == { this.CanFocus }");
}

private void CanFocusTimer_Tick(object sender, EventArgs e)
{
    (sender as System.Windows.Forms.Timer).Stop();

    // Even though there is already a MessageBox shown the second gets
    // displayed. But now CanFocus == false
    MessageBox.Show($"Second MessageBox: { nameof(this.CanFocus) } == { this.CanFocus }");
}

Result:

enter image description here


Answers:


No comments:

Post a Comment