5

TL;DR

While a .ShowDialog() modal dialog is open and the user clicks on the original form, the dialog's title bar flashes. Is that event accessible via the Windows.Forms API, or by any other means?


Details

This is a standard C# 6 Windows Forms project with a parent form and a dialog window. The parent form has a single button that opens the dialog:

using System;
using System.Windows.Forms;

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        using (var dialog = new Dialog())
        {
            Console.WriteLine("Dialog starting.");

            dialog.ShowDialog(this);

            Console.WriteLine("Dialog done.");
        }
    }
}

The Dialog that is created by .ShowDialog(this) is equally simple, with an OK button and a Cancel button:

using System;
using System.Windows.Forms;

public partial class Dialog : Form
{
    public Dialog()
    {
        InitializeComponent();
    }

    private void btnOK_Click(object sender, EventArgs e)
    {
        Close();
    }

    private void btnCancel_Click(object sender, EventArgs e)
    {
        Close();
    }
}

The application starts,

enter image description here

and when the user clicks on the "Show Modal Dialog" button, the button1 event Click is fired, and the dialog is triggered as shown in the first snippet.

enter image description here

When the user clicks on the original form while the dialog is still open, the dialog's title bar flashes.

enter image description here

Is that event accessible via the Windows.Forms API, or by any other means?

In a more complicated application, I would like to close the modal dialog when the user click back on the main form if the dialog's input fields pass validation, and highlight the invalid fields if not.

I'm currently showing the dialog using the .Show() method, and closing the dialog on the deactivate event. But this has two disadvantages

  • When the user clicks on the desktop or another application, the dialog closes.
  • When the user clicks off the dialog, sometimes the main form is hidden behind the window of a different application.

I found a related WPF question, and the answer was a pretty concrete "no".

Community
  • 1
  • 1
kdbanman
  • 10,161
  • 10
  • 46
  • 78
  • If not an event; you can try a work around. If user clicks on main window and the dialog is open, try setting property / call a method on child dialog to close it self. You can track the click event of main window. And i am not sure if the main window will be able to recieve the click event when the child is shown as dialog, as usually child forms are opened with ShowDialog() to avoid focus to main window. – Orion_Eagle Nov 04 '15 at 23:23
  • Such popups are implemented by using the Capture property, it ensures you can see clicks outside of the window area. But that's incompatible with windows that use controls that use Capture themselves, like Button. Creating your own ContextMenuStrip is not a good idea, just use the one in the toolbox. – Hans Passant Nov 04 '15 at 23:33
  • 1
    @Orion_Eagle, nice thought. But unfortunately the click event of the main form is not thrown if the dialog is still open, because the `.ShowDialog()` has not returned. (I *think* the main form's GUI event loop is frozen until `.ShowDialog()` returns, but I'm not positive.) – kdbanman Nov 04 '15 at 23:45
  • @HansPassant, I'm totally unfamiliar with the `Capture` property, so I'm not sure how to apply it here. I'm going to start researching now - any guidance is appreciated. Thanks for the response. – kdbanman Nov 04 '15 at 23:47

2 Answers2

3

overriding WndProc is the way to go, as Orion_Eagle suggests. Check out this list of windows messages

protected override void WndProc(ref Message m)
{
    //134 = WM_NCACTIVATE
    if (m.Msg == 134)
    {       
        //Check if other app is activating - if so, we do not close         
        if (m.LParam == IntPtr.Zero)
        {                    
             if (m.WParam != IntPtr.Zero)
             {                     
                 //Other form in our app has focus
             }

        }
     }                     

     base.WndProc(ref m);
}
TDull
  • 753
  • 5
  • 12
1

Check this post; override WndProc method, it has all the events you need.

    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);
        Console.WriteLine(m.Msg);
    }

This might help you.

Community
  • 1
  • 1
Orion_Eagle
  • 124
  • 5