C# 当用户在窗体窗口外单击时如何关闭窗体?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/298491/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 22:10:28  来源:igfitidea点击:

How do I close a form when a user clicks outside the form's window?

c#formsclick

提问by Simon

I want to close a System.Windows.Forms.Form if the user clicks anywhere outside it. I've tried using IMessageFilter, but even then none of the messages are passed to PreFilterMessage. How do I receive clicks outside a form's window?

如果用户单击 System.Windows.Forms.Form 之外的任何地方,我想关闭它。我试过使用 IMessageFilter,但即使如此,也没有任何消息传递给 PreFilterMessage。如何接收表单窗口外的点击?

采纳答案by Simon

With thanks to p-daddyin this question, I've found this solution which allows me to use ShowDialog:

感谢p-daddy这个问题中,我找到了这个允许我使用 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);
}

回答by Galwegian

If it is a child form in an MDI application, you could trap the click in the parent form, otherwise the solution will be messy.

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

I am not convinced what you suggest represents intuitive UI behaviour anyway. Are you sure that is the best design?

无论如何,我不相信你的建议代表了直观的 UI 行为。你确定这是最好的设计吗?

回答by MusiGenesis

In your form's Deactivate event, put "this.Close()". Your form will close as soon as you click anywhere else in Windows.

在表单的 Deactivate 事件中,放置“this.Close()”。只要您单击 Windows 中的其他任何位置,您的表单就会关闭。

Update: I think what you have right now is a Volume button, and inside the Click event you create an instance of your VolumeSlider form and make it appear by calling ShowDialog() which blocks until the user closes the popped-up form. In the next line you read the volume the user selected and use it in your program.

更新:我认为您现在拥有的是一个 Volume 按钮,在 Click 事件中,您创建了 VolumeSlider 表单的一个实例,并通过调用 ShowDialog() 使其出现,该实例会阻塞直到用户关闭弹出的表单。在下一行中,您读取用户选择的卷并在您的程序中使用它。

This is OK, but as you've noticed it forces the user to explicitly close the popup in order to get back to the main program. Show() is the method you really want to use here on your popup form, but Show() doesn't block which means the Click event back on your main form finishes without knowing what the new volume is supposed to be.

这没问题,但正如您已经注意到的那样,它会强制用户显式关闭弹出窗口以返回主程序。Show() 是您真正想在弹出窗体上使用的方法,但 Show() 不会阻塞,这意味着主窗体上的 Click 事件在不知道新卷应该是什么的情况下完成。

A simple solution is to create a public method on your main form like this:

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

public void SetVolume(int volume)
{
    // do something with the volume - whatever you did before with it
}

Then, in your Volume button's Click event (also on the main form), you make the VolumeSlider appear like so:

然后,在您的 Volume 按钮的 Click 事件(也在主窗体上)中,您使 VolumeSlider 看起来像这样:

VolumeSlider slider = new VolumeSlider();
slider.Show(this); // the "this" is needed for the next step

In the VolumeSlider form, as the user works the (I guess) scrollbar, you put this code in the scrollbar's ValueChanged event (I think that's what it is):

在 VolumeSlider 表单中,当用户操作(我猜)滚动条时,您将此代码放在滚动条的 ValueChanged 事件中(我认为就是这样):

MainForm owner = (MainForm)this.Owner;
owner.SetVolume(scrollbar.Value);

And then in the VolumeSlider form's Deactivate event you would put this.Close() as mentioned above. Your form will then behave as expected.

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

回答by MusiGenesis

If you are trying to make a popup window that behaves a little bit like a menu, except that it lets you interact with your controls, you could try hosting a usercontrol inside a toolstrip dropdown.

如果您正在尝试制作一个行为有点像菜单的弹出窗口,除了它允许您与控件交互之外,您可以尝试在工具条下拉列表中托管用户控件。

回答by rkraen

With Simon's solution I had the same Problem describt by Noam. With following code I've avoid the "Click through" problem...

使用西蒙的解决方案,我得到了与诺姆相同的问题描述。使用以下代码,我避免了“点击”问题...

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

回答by Sharif Lotfi

SIMPLY WAY : on Form1 use this code to call form2:

简单的方法:在 Form1 上使用此代码调用 form2:

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles     Button1.Click
    Form2.Owner = Me
    Form2.Show()
End Sub

and then use this code on form1 again :

然后再次在 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

回答by Hiep Nguyen

this is simple :

这很简单:

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