关于c#:Winforms:在对话框外部单击时,关闭模式对话框

Winforms: Close modal dialog when clicking outside the dialog

我有一个打开的模式对话框(Windows窗体)。 我想要在对话框外部(在父窗体上)单击时关闭对话框。 我怎样才能做到这一点?


您应该将其更改为非模式对话框(使用Show(..)打开它),然后使用Deactivate事件并关闭它。


有一些原因(例如框架变通办法等)迫使人们使用模式对话框。您可以通过覆盖表单方法WndProc来模拟Deactivate事件,如下所示:

1
2
3
4
5
6
7
8
9
protected override void WndProc(ref Message m) {
    const UInt32 WM_NCACTIVATE = 0x0086;

    if (m.Msg == WM_NCACTIVATE && m.WParam.ToInt32() == 0) {
        handleDeactivate();
    } else {
        base.WndProc(ref m);
   }
}

发送WM_NCACTIVATE消息以告知表单以指示它是活动的(WParam == 1)还是非活动的(WParam == 0)。如果您单击父窗体上的某个位置,您的模式对话框将开始"闪烁活动",告诉您,这现在更重要。这可以通过多次发送前面提到的消息来实现(停用->激活->停用-> ...->激活)。

但是要小心,如果handleDeactivate()方法没有终止您的表单,则每次停用消息出现时都会调用该方法。您必须自己处理。

链接:
MSDN论坛
MSDN文档


那行不通,您必须使用Show()来触发Deactivate事件。

对话框将禁用所有其他窗口以使其成为模态。因此,在最大化父对话框的情况下,在对话框窗口之外无法单击任何内容。因此,停用事件不会触发。相反,当您使用Show(owner)方法时,ShowDialog()的这种副作用不再受阻,并且停用即可。使用FormClosing / Closed事件来执行ShowDialog()调用之后的操作。

通常,通过使用上下文菜单栏或菜单下拉菜单来完成此操作,方法是捕获鼠标Control.Capture属性。这样您甚至可以在窗口之外检测鼠标事件。但这不能与窗体可靠地一起使用,窗体内的控件将使用Capture属性供其自己使用。因此,请坚持使用"显示并停用"。


使用.Show()而不是.ShowDialog()。

以子形式处理停用事件。

1
2
3
4
private void frmAdvancedSearch_Deactivate(object sender, EventArgs e)
    {
        this.Close();
    }

当用户在子级外部单击时,这将关闭子级表单。

如果您在孩子关闭后使用.ShowDialog()做某事,
使用.show()并覆盖父级中子级的" formclosing"事件。因此,当子窗体关闭并在那里执行您的操作时,它将命中。

1
2
advancedSearch.FormClosing += AdvancedSearch_FormClosing;
advancedSearch.ShowDialog();
1
2
3
4
5
6
7
8
private void AdvancedSearch_FormClosing(object sender, FormClosingEventArgs e)
    {
        var advanceSearch = sender as frmAdvancedSearch;
        if (advanceSearch.SelectedItem != null)
        {
            myColumnComboBox.Text = advanceSearch.SelectedItem.Name;
        }
    }

希望这可以帮助。


您好,我认为您可以在事件中使用鼠标按下事件或按下键盘事件来找到鼠标所在的位置(如果该位置为负值),这意味着您已经选择了窗口的外部区域,然后关闭该窗口
希望有帮助。