C# 当用户在表单外单击时,如何关闭表单';窗户在哪里?

C# 当用户在表单外单击时,如何关闭表单';窗户在哪里?,c#,forms,click,C#,Forms,Click,如果用户单击System.Windows.Forms.Form之外的任何位置,我想关闭它。我尝试过使用IMessageFilter,但即使这样,也没有消息传递给PreFilterMessage。如何在窗体窗口外接收单击?如果它是MDI应用程序中的子窗体,则可以在父窗体中捕获单击,否则解决方案会很混乱 我不相信你的建议代表了直观的用户界面行为。您确定这是最好的设计吗?在表单的停用事件中,输入“this.Close()”。只要单击Windows中的任何其他位置,表单将立即关闭 更新:我认为您现在拥有

如果用户单击System.Windows.Forms.Form之外的任何位置,我想关闭它。我尝试过使用IMessageFilter,但即使这样,也没有消息传递给PreFilterMessage。如何在窗体窗口外接收单击?

如果它是MDI应用程序中的子窗体,则可以在父窗体中捕获单击,否则解决方案会很混乱


我不相信你的建议代表了直观的用户界面行为。您确定这是最好的设计吗?

在表单的停用事件中,输入“this.Close()”。只要单击Windows中的任何其他位置,表单将立即关闭

更新:我认为您现在拥有的是一个音量按钮,在单击事件中,您创建了一个VolumeSlider窗体的实例,并通过调用ShowDialog()使其显示,该对话框将一直阻止,直到用户关闭弹出的窗体。在下一行中,您将读取用户选择的卷,并在程序中使用它

这是可以的,但正如您所注意到的,它会强制用户显式关闭弹出窗口以返回主程序。Show()是您真正希望在弹出窗体上使用的方法,但是Show()不会阻止,这意味着返回主窗体的单击事件将在不知道新卷应该是什么的情况下完成

一个简单的解决方案是在主窗体上创建一个公共方法,如下所示:

public void SetVolume(int volume)
{
    // do something with the volume - whatever you did before with it
}
然后,在音量按钮的单击事件(也在主窗体上)中,使VolumeSlider如下所示:

VolumeSlider slider = new VolumeSlider();
slider.Show(this); // the "this" is needed for the next step
在VolumeSlider表单中,当用户操作(我猜)滚动条时,您将此代码放入滚动条的ValueChanged事件中(我想就是这样):


然后,在VolumeSlider表单的Deactivate事件中,您将放置这个.Close(),如上所述。然后,您的表单将按预期运行。

如果您试图创建一个有点像菜单的弹出窗口,除了它允许您与控件交互之外,您可以尝试在toolstrip下拉列表中托管一个usercontrol。

多亏了in,我找到了允许我使用ShowDialog的解决方案:

protected override void OnShown(EventArgs e)
{
    base.OnShown(e);
    this.Capture = true;
}

protected override void OnCaptureChanged(EventArgs e)
{
    if (!this.Capture)
    {
        if (!this.RectangleToScreen(this.DisplayRectangle).Contains(Cursor.Position))
        {
            this.Close();
        }
        else
        {
            this.Capture = true;
        }
    }

    base.OnCaptureChanged(e);
}

对于西蒙的解决方案,诺姆也描述了同样的问题。通过以下代码,我避免了“点击通过”问题

protected override void WndProc(ref Message m)
{    
    base.WndProc(ref m);

    // if click outside dialog -> Close Dlg
    if (m.Msg == NativeConstants.WM_NCACTIVATE) //0x86
    {
        if (this.Visible)
        {
            if (!this.RectangleToScreen(this.DisplayRectangle).Contains(Cursor.Position))
                this.Close();
        }
    }
}
简单地说: 在Form1上,使用此代码调用form2:

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles     Button1.Click
    Form2.Owner = Me
    Form2.Show()
End Sub
然后在form1上再次使用此代码:

Private Sub Form1_MouseClick(sender As Object, e As MouseEventArgs) Handles Me.MouseClick
    If Form2.IsHandleCreated = True Then
        Form2.Close()
    End If
End Sub
这很简单:

private void button1_Click(object sender, EventArgs e)
    {
        Form f = new Form();
        f.LostFocus +=new EventHandler(f_LostFocus);
        f.Show();
    }

    void f_LostFocus(object sender, EventArgs e)
    {
        Form f = sender as Form;
        f.Close();
        f.Dispose();
    }

您应该使用停用
我有一个名为Form2的表单
在属性窗口的停用部分
您将名称声明为Form2\u Deactivate
Form2.cs文件中:

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

这是一个音量滑块-这似乎是其他人实现它们的方式。这与下拉框没有太大区别-只要你单击其他地方,选择列表就会消失。我:“医生,我这样做会很痛。”医生:“不要那样做。”马上看我上面的更新。让我知道它是否适合你。我不喜欢同时发牢骚和犯错。:)@杰森帕克:当然有:我找到了!谢谢正是我想要的。嗯。。。毕竟它并没有像预期的那样工作——当表单加载时,我有“手动”鼠标光标,任何在表单外的点击都会关闭它。如果我想与表单本身进行交互,第一次单击似乎只清除“捕获”,并且不会在表单内部注册(例如,单击复选框不会选中它),然后单击外部不会关闭窗口。还有别的方法吗?@Noam:你的身体有多简单?如果它只有一个孩子,你可以设置孩子的捕获,而不是表单的捕获。它是OnMouseCaptureChanged而不是onCaptureChange我在VisibleChanged和OnMouseCaptreChanged上使用的,它可以工作,但有时鼠标是隐藏的。你能提供一些关于这个答案的上下文,让某人正确使用它吗?这是真正正确的答案。在使用
ShowDialog()
打开的表单外部单击时,将发送3条消息:,和。不要使用第三个,但是第二个(
WM_ACTIVATE
)可能比第一个更好。另外,不要忘记设置
对话框结果
private void Form2_Deactivate(object sender, EventArgs e)
{
    this.Close();
}