【问题标题】:How do I close a form when a user clicks outside the form's window?当用户在表单窗口外单击时,如何关闭表单?
【发布时间】:2008-11-18 11:29:20
【问题描述】:

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

【问题讨论】:

    标签: c# forms click


    【解决方案1】:

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

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

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

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

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

    然后,在音量按钮的 Click 事件中(也在主窗体上),使 VolumeSlider 如下所示:

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

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

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

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

    【讨论】:

    • 我:“医生,我这样做会很痛。”医生:“不要那样做。”请稍后查看我的更新。
    • 让我知道它是否适合您。我讨厌同时刻薄和错误。 :)
    • @JesonPark:当然可以:msdn.microsoft.com/en-us/library/…
    • tnx MusiGenesis 我找到了!
    【解决方案2】:

    感谢this question 中的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);
    }
    

    【讨论】:

    • 谢谢。正是我想要的。
    • mm... 毕竟它没有按预期工作 - 当表单加载时,我有“手”鼠标光标,并且在表单外的任何点击都会关闭它。如果我想与表单本身进行交互,第一次单击似乎只清除“捕获”,并且不会在表单内部注册(例如,单击复选框不会选中它),然后单击外部不会关闭窗户。有没有其他方法可以做到这一点?
    • @Noam:你的表格有多简单?如果它只有一个孩子,您可以设置孩子的捕获而不是表单的。
    • 是 OnMouseCaptureChanged 不是 OnCaptureChanged
    • 我使用了 OnVisibleChanged 和 OnMouseCaptreChanged,它可以工作,但有时鼠标是隐藏的。
    【解决方案3】:

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

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

    【讨论】:

    • 您能否提供有关此答案的一些上下文以使某人能够正确使用它?
    • 这是真正正确的答案。当您在使用ShowDialog() 打开的表单外部单击时,将发送 3 条消息:WM_NCACTIVATEWM_ACTIVATEWM_ACTIVATEAPP。不要使用第三个,但第二个 (WM_ACTIVATE) 可能比第一个更好。也不要忘记设置DialogResult
    【解决方案4】:

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

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

    【讨论】:

      【解决方案5】:

      如果是MDI应用中的子窗体,可以在父窗体中捕获点击,否则解决办法会很乱。

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

      【讨论】:

      • 这是一个音量滑块 - 这似乎是其他人实现它们的方式。
      • 这与下拉框没有太大区别 - 一旦您单击其他位置,选择列表就会消失。
      【解决方案6】:

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

      【讨论】:

        【解决方案7】:

        简单的方法: 在 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
        

        【讨论】:

          【解决方案8】:

          这很简单:

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

          【讨论】:

          • 这对我有用!其他解决方案只是笨拙,尤其是使用 OnDeactivate() 的解决方案,它使我的整个应用程序在关闭子表单时将焦点转移到一个完全其他的应用程序上,出于某种原因 (??)...
          猜你喜欢
          • 2023-04-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-06-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多