简体   繁体   English

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

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

I want to close a System.Windows.Forms.Form if the user clicks anywhere outside it.如果用户单击 System.Windows.Forms.Form 之外的任何地方,我想关闭它。 I've tried using IMessageFilter, but even then none of the messages are passed to PreFilterMessage.我试过使用 IMessageFilter,但即使如此,也没有任何消息传递给 PreFilterMessage。 How do I receive clicks outside a form's window?如何接收表单窗口外的点击?

In your form's Deactivate event, put "this.Close()".在表单的 Deactivate 事件中,放置“this.Close()”。 Your form will close as soon as you click anywhere else in Windows.只要您单击 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.更新:我认为您现在拥有的是一个 Volume 按钮,在 Click 事件中,您创建了 VolumeSlider 表单的一个实例,并通过调用 ShowDialog() 使其出现,该实例会阻塞直到用户关闭弹出的表单。 In the next line you read the volume the user selected and use it in your program.在下一行中,您读取用户选择的卷并在您的程序中使用它。

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.然后在 VolumeSlider 表单的 Deactivate 事件中,您将如上所述放置 this.Close()。 Your form will then behave as expected.您的表单将按预期运行。

With thanks to p-daddy in 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);
}

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

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.无论如何,我不相信你的建议代表了直观的 UI 行为。 Are you sure that is the best design?你确定这是最好的设计吗?

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

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

You should use Deactivate :您应该使用Deactivate
I have a form called Form2 .我有一个名为Form2的表单。
In the Deactivate section of the Properties window.在“属性”窗口的“停用”部分。
You declare the name Form2_Deactivate .您声明名称Form2_Deactivate
In the Form2.cs file:Form2.cs文件中:

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM