【问题标题】:Is there an event thrown when a user tries to click off a modal dialog created with Form.ShowDialog()?当用户尝试单击使用 Form.ShowDialog() 创建的模式对话框时是否会引发事件?
【发布时间】:2016-02-05 15:48:59
【问题描述】:

TL;DR

.ShowDialog() 模态对话框打开并且用户单击原始表单时,对话框的标题栏会闪烁。是否可以通过Windows.Forms API 或任何其他方式访问该事件?


详情

这是一个标准的 C# 6 Windows 窗体项目,带有一个父窗体和一个对话框窗口。父窗体有一个打开对话框的按钮:

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

.ShowDialog(this) 创建的Dialog 同样简单,带有一个确定按钮和一个取消按钮:

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();
    }
}

应用程序启动,

当用户点击“显示模态对话框”按钮时,会触发button1事件Click,并触发对话框,如第一个sn-p所示。

当用户在对话框仍然打开的情况下单击原始表单时,对话框的标题栏会闪烁。

是否可以通过Windows.Forms API 或任何其他方式访问该事件?

在更复杂的应用程序中,如果对话框的输入字段通过验证,我想在用户单击主窗体时关闭模式对话框,如果没有通过验证,则突出显示无效字段。

我目前正在使用.Show() 方法显示dialog,并在deactivate 事件上关闭dialog。但这有两个缺点

  • 当用户点击桌面或其他应用程序时,dialog 关闭。
  • 当用户点击关闭对话框时,有时主窗体会隐藏在其他应用程序的窗口后面。

我找到了related WPF question,答案是一个非常具体的“no”。

【问题讨论】:

  • 如果不是事件;您可以尝试解决方法。如果用户单击主窗口并且对话框打开,请尝试在子对话框上设置属性/调用方法以自行关闭它。您可以跟踪主窗口的点击事件。而且我不确定当孩子显示为对话框时主窗口是否能够接收到点击事件,因为通常使用 ShowDialog() 打开子表单以避免焦点到主窗口。
  • 这样的弹出窗口是通过使用 Capture 属性实现的,它确保您可以看到窗口区域之外的点击。但这与使用自身使用 Capture 的控件的窗口不兼容,例如 Button。创建自己的 ContextMenuStrip 不是一个好主意,只需使用工具箱中的那个即可。
  • @Orion_Eagle,好主意。但不幸的是,如果对话框仍然打开,则不会抛出主窗体的单击事件,因为 .ShowDialog() 尚未返回。 (我认为主窗体的 GUI 事件循环在.ShowDialog() 返回之前被冻结,但我并不肯定。)
  • @HansPassant,我完全不熟悉Capture 属性,所以我不确定如何在这里应用它。我现在要开始研究 - 感谢任何指导。感谢您的回复。

标签: c# winforms events modal-dialog


【解决方案1】:

正如 Orion_Eagle 所建议的那样,重写 WndProc 是可行的方法。 查看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);
}

【讨论】:

    【解决方案2】:

    检查这个post;覆盖 WndProc 方法,它有你需要的所有事件。

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

    这可能会对你有所帮助。

    【讨论】:

    • 这看起来像一棵值得一树的树。谢谢。
    猜你喜欢
    • 2017-01-16
    • 1970-01-01
    • 2015-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多