Winforms:点击对话框外部时关闭模态对话框

24

我有一个打开的模态对话框(Windows Forms)。我想让它在点击对话框外部(父窗体)时关闭。我该怎么做?


3
这让我感到很可疑。如果你希望用户在点击对话框外部时将其关闭,为什么要使用“模态”对话框?模态对话框的整个意义在于不能被忽略——在允许用户继续使用应用程序之前,必须选择对话框中提供的选项。很可能,你需要使用一个普通的非模态对话框,或者重新考虑你的设计。 - Cody Gray
此外,这是一个完全重复的问题:http://stackoverflow.com/questions/3856301/c-close-modal-form-when-mouse-click-outside-form-area。正如那个问题的答案所指出的那样,您需要捕获鼠标才能检测到这些单击事件。 - Cody Gray
6个回答

30

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


这就是我的问题的解决方案! - Kottan

10

有时候(例如,框架回避等原因)我们不得不使用模态对话框。你可以通过重写窗体方法WndProc来模拟Deactivate事件,像这样:

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 文档


6

无法使用此方法,您必须使用Show()来触发Deactivate事件。

对话框会禁用所有其他窗口以使自身模态。因此,在父窗口最大化时,外部无法单击任何内容。相应地,Deactivate事件不会触发。当您改用Show(owner)方法时,ShowDialog()的这种副作用不再成为问题,而Deactivate则正常工作。使用FormClosing / Closed事件来执行ShowDialog()调用后要执行的操作。

通常使用上下文菜单或菜单下拉列表等方式来实现此功能,是通过捕获鼠标(Control.Capture属性)来检测窗口外的鼠标事件。但是,对于窗体,这样做可能无法可靠地工作,因为窗体内的控件将使用Capture属性进行自身的操作。因此,请使用Show和Deactivate。


3

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

在子窗体中处理Deactivate事件。

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

这将在用户在子窗体外单击时关闭子窗体。
如果您使用.ShowDialog()执行子窗口关闭后的操作,请使用.Show()并在父窗口中重写 'formclosing' 事件。这样当子窗口关闭时,就会触发该事件并在那里执行您的操作。
advancedSearch.FormClosing += AdvancedSearch_FormClosing;
advancedSearch.ShowDialog();

private void AdvancedSearch_FormClosing(object sender, FormClosingEventArgs e)
    {
        var advanceSearch = sender as frmAdvancedSearch;
        if (advanceSearch.SelectedItem != null)
        {
            myColumnComboBox.Text = advanceSearch.SelectedItem.Name;
        }
    }

希望这能帮到您。

0

嗨,我认为您可以在事件中使用鼠标按下事件或键按下事件来查找鼠标的位置,如果该位置为负值,则表示您选择了窗口的外部区域,然后关闭该窗口。希望这可以帮到您。


尝试过了...如果在模态对话框外单击,事件不会被调用。 - pogojotz

0

您可以使用 this.ParentForm.MouseClick += ParentForm_MouseClick,同时也可以

this.ParentForm.Click += ParentForm_Click

然后关闭你的表单。

private void ParentForm_MouseClick(object sender, MouseEventArgs e)
{
   this.Close();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接