Link to home
Start Free TrialLog in
Avatar of Russ Suter
Russ Suter

asked on

How can I detect if a modal dialog is currently open in my application?

A while back I needed to add scroll wheel functionality to a panel. I am using this bit of code to capture and process the wheel messages and it works fine.
		public bool PreFilterMessage(ref Message m)
		{
			if (m.Msg == MSG.WM_MOUSEWHEEL)
			{
				if (recipientControl.Parent.ClientRectangle.Contains(recipientControl.PointToClient(System.Windows.Forms.Control.MousePosition)))
				{
					NativeMethods.SendMessage(recipientControl.Handle, m.Msg, m.WParam, m.LParam);
					return true;
				}
			}
			return false;
		}

Open in new window

There's just one problem, it processes the message even if another window is open on top of the main window. If I open another window using the ShowDialog() method it should block mousewheel handling for the panel in the underlying form. I just don't know how to detect whether or not a dialog is currently open. Can anyone help with this?
Avatar of Obadiah Christopher
Obadiah Christopher
Flag of India image

Window.ShowModalDialog() ?
Avatar of Russ Suter
Russ Suter

ASKER

Was that just a guess? Because that isn't even a method defined in the .NET library. If you mean Window.ShowModal() then that's used to display a form as a modal dialog. That won't tell me if a dialog is currently being displayed at the time of message capture.
You could pass an instance of the parent form to your filter and then check for the TopMost or ContainsFocus property, e.g. -

Form1.cs -
using System;
using System.Windows.Forms;

namespace EE_Q29148449
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            Application.AddMessageFilter(new ScrollingFilter(this, richTextBox1));
        }

        private void OnClick(object sender, EventArgs e)
        {
            var frm2 = new Form2();
            frm2.ShowDialog();
        }
    }
}

Open in new window

Form1.Designer.cs -
namespace EE_Q29148449
{
    partial class Form1
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.richTextBox1 = new System.Windows.Forms.RichTextBox();
            this.splitContainer1 = new System.Windows.Forms.SplitContainer();
            this.button1 = new System.Windows.Forms.Button();
            ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
            this.splitContainer1.Panel1.SuspendLayout();
            this.splitContainer1.Panel2.SuspendLayout();
            this.splitContainer1.SuspendLayout();
            this.SuspendLayout();
            // 
            // richTextBox1
            // 
            this.richTextBox1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.richTextBox1.Location = new System.Drawing.Point(0, 0);
            this.richTextBox1.Name = "richTextBox1";
            this.richTextBox1.Size = new System.Drawing.Size(800, 402);
            this.richTextBox1.TabIndex = 0;
            this.richTextBox1.Text = "";
            // 
            // splitContainer1
            // 
            this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.splitContainer1.Location = new System.Drawing.Point(0, 0);
            this.splitContainer1.Name = "splitContainer1";
            this.splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal;
            // 
            // splitContainer1.Panel1
            // 
            this.splitContainer1.Panel1.Controls.Add(this.richTextBox1);
            // 
            // splitContainer1.Panel2
            // 
            this.splitContainer1.Panel2.Controls.Add(this.button1);
            this.splitContainer1.Size = new System.Drawing.Size(800, 450);
            this.splitContainer1.SplitterDistance = 402;
            this.splitContainer1.TabIndex = 1;
            // 
            // button1
            // 
            this.button1.Location = new System.Drawing.Point(339, 11);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(122, 23);
            this.button1.TabIndex = 3;
            this.button1.Text = "Open Modal";
            this.button1.UseVisualStyleBackColor = true;
            this.button1.Click += new System.EventHandler(this.OnClick);
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(800, 450);
            this.Controls.Add(this.splitContainer1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.splitContainer1.Panel1.ResumeLayout(false);
            this.splitContainer1.Panel2.ResumeLayout(false);
            ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();
            this.splitContainer1.ResumeLayout(false);
            this.ResumeLayout(false);

        }

        #endregion

        private System.Windows.Forms.RichTextBox richTextBox1;
        private System.Windows.Forms.SplitContainer splitContainer1;
        private System.Windows.Forms.Button button1;
    }
}

Open in new window

Form2.cs -
using System;
using System.Windows.Forms;

namespace EE_Q29148449
{
    public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
        }

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

Open in new window

Form2.Designer.cs -
namespace EE_Q29148449
{
    partial class Form2
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.button1 = new System.Windows.Forms.Button();
            this.SuspendLayout();
            // 
            // button1
            // 
            this.button1.Location = new System.Drawing.Point(54, 27);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(75, 23);
            this.button1.TabIndex = 2;
            this.button1.Text = "Close Modal";
            this.button1.UseVisualStyleBackColor = true;
            this.button1.Click += new System.EventHandler(this.OnClick);
            // 
            // Form2
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(182, 77);
            this.Controls.Add(this.button1);
            this.Name = "Form2";
            this.Text = "Form2";
            this.ResumeLayout(false);

        }

        #endregion

        private System.Windows.Forms.Button button1;
    }
}

Open in new window

ScrollingFilter.cs -
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace EE_Q29148449
{
    class ScrollingFilter : IMessageFilter
    {
        const int WM_MOUSEWHEEL = 0x020A;

        private Form instance;
        private Control control;

        [DllImport("user32.dll")]
        static extern int SendMessage(IntPtr handle, int msg, int wParam, int lParam);

        public ScrollingFilter(Form instance, Control control)
        {
            this.instance = instance;
            this.control = control;
        }

        bool IMessageFilter.PreFilterMessage(ref Message m)
        {
            if (m.Msg == 0x020A && (instance.TopMost || instance.ContainsFocus))
            {
                MessageBox.Show($"{{ Handle: {m.HWnd}, LParam: {m.LParam}, Message: {m.Msg}, WParam: {m.WParam}, Result: {m.Result} }}{Environment.NewLine}");
                return true;
            }
            return false;
        }
    }
}

Open in new window

Which produces the following results -

With Form1 focused and moving the mouse wheel -User generated imageOpening the modal and moving the mouse wheel produces nothing -User generated imageBear in mind that this means your form must be focused and be top most in order to process mouse wheel messages.

-saige-
I've just stumbled upon an answer and it turns out it's ridiculously simple.

I can just use System.Windows.Forms.Application.OpenForms and look for the last one. If the last one in the collection isn't my main window then I know a dialog is showing.
Glad you got it sorted...

-saige-
ASKER CERTIFIED SOLUTION
Avatar of Russ Suter
Russ Suter

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
You could also use LINQ -
!Application.OpenForms.Cast<Form>().Any(f => f is MyForm)

Open in new window

-saige-