我有一个C#/。NET应用程序,我想实现以下行为:
我有一个弹出菜单。每当用户点击 内的任何 弹出菜单时,我都希望弹出菜单关闭。
但是,每当用户不在应用程序中时,我都不希望发生任何事情。
我正在尝试通过LostFocus事件来管理它,但我无法确定我的应用程序是否是活动窗口。代码看起来像这样。
private void Button_LostFocus(object sender, System.EventArgs e)
{
if (InActiveWindow()) {
CloseMenu()
}
else {
// not in active window, do nothing
}
}
我需要知道的是如何实现InActiveWindow()方法。
答案 0 :(得分:4)
您可以P / Invoke到GetForegroundWindow(),并将返回的HWND与应用程序的form.Handle属性进行比较。
获得句柄后,您还可以P / Invoke GetAncestor()获取root权限窗口。这应该是应用程序主要启动窗口的句柄,如果它在您的应用程序中。
答案 1 :(得分:2)
我在处理项目时偶然发现了你的问题并基于Reed Copsey's answer,我写了这个快速代码,似乎做得很好。
这是代码:
Public Class Form1
'''<summary>
'''Returns a handle to the foreground window.
'''</summary>
<Runtime.InteropServices.DllImport("user32.dll", SetLastError:=True)> _
Private Shared Function GetForegroundWindow() As IntPtr
End Function
'''<summary>
'''Gets a value indicating whether this instance is foreground window.
'''</summary>
'''<value>
'''<c>true</c> if this is the foreground window; otherwise, <c>false</c>.
'''</value>
Private ReadOnly Property IsForegroundWindow As Boolean
Get
Dim foreWnd = GetForegroundWindow()
Return ((From f In Me.MdiChildren Select f.Handle).Union(
From f In Me.OwnedForms Select f.Handle).Union(
{Me.Handle})).Contains(foreWnd)
End Get
End Property
End Class
我没有太多时间将它转换为C#,因为我正在处理一个截止日期为2天的项目,但我相信你可以快速完成转换。
这是VB.NET代码的C#版本:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
///<summary>Gets a value indicating whether this instance is foreground window.</summary>
///<value><c>true</c> if this is the foreground window; otherwise, <c>false</c>.</value>
private bool IsForegroundWindow
{
get
{
var foreWnd = GetForegroundWindow();
return ((from f in this.MdiChildren select f.Handle)
.Union(from f in this.OwnedForms select f.Handle)
.Union(new IntPtr[] { this.Handle })).Contains(foreWnd);
}
}
}
答案 2 :(得分:1)
这似乎是最棘手的原因,因为弹出窗口在主窗体停用之前失去焦点,因此活动窗口将始终在此事件发生时位于应用程序中。实际上,您想知道在事件结束后它是否仍然是活动窗口。
你可以设置某种方案,让你记住弹出窗口正在失去焦点,抛弃你需要关闭它的事实,以及在LostFocus
或Deactivate
事件中应用程序的主要表单取消注释,告诉您需要关闭它;但问题是你什么时候处理这个音符?
我认为这可能会更容易,至少如果弹出窗口是主窗体的直接子窗口(我怀疑在你的情况下可能是)挂钩Focus
或甚至{{1主窗体的事件,如果它是打开的,则使用它关闭弹出窗口(可能通过扫描其实现ICloseOnLostFocus接口的子窗体列表,以便弹出窗口有机会参与决策并执行任何操作否则它需要做。)
我希望我知道一个更好的文档,解释所有这些事件实际上意味着什么,以及它们如何相互排序,MSDN在描述它们时还有很多不足之处。