【发布时间】:2008-11-18 11:29:20
【问题描述】:
如果用户单击 System.Windows.Forms.Form 外部的任何位置,我想关闭它。我尝试过使用 IMessageFilter,但即便如此,也没有任何消息传递给 PreFilterMessage。如何接收表单窗口外的点击?
【问题讨论】:
如果用户单击 System.Windows.Forms.Form 外部的任何位置,我想关闭它。我尝试过使用 IMessageFilter,但即便如此,也没有任何消息传递给 PreFilterMessage。如何接收表单窗口外的点击?
【问题讨论】:
在表单的 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() 如上所述。然后,您的表单将按预期运行。
【讨论】:
感谢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);
}
【讨论】:
使用西蒙的解决方案,我遇到了诺姆描述的相同问题。使用以下代码,我避免了“点击通过”问题...
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_NCACTIVATE、WM_ACTIVATE 和 WM_ACTIVATEAPP。不要使用第三个,但第二个 (WM_ACTIVATE) 可能比第一个更好。也不要忘记设置DialogResult!
您应该使用停用:
我有一个名为 Form2 的表单。
在属性窗口的停用部分。
您声明名称 Form2_Deactivate。
在 Form2.cs 文件中:
private void Form2_Deactivate(object sender, EventArgs e)
{
this.Close();
}
【讨论】:
如果是MDI应用中的子窗体,可以在父窗体中捕获点击,否则解决办法会很乱。
无论如何,我不相信您的建议代表直观的 UI 行为。你确定这是最好的设计吗?
【讨论】:
如果您尝试制作一个类似于菜单的弹出窗口,除了它允许您与控件交互之外,您可以尝试在工具条下拉列表中托管一个用户控件。
【讨论】:
简单的方法: 在 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();
}
【讨论】: