确定Program是否是.NET中的活动窗口

时间:2009-05-21 15:58:05

标签: c# .net user-interface active-window

我有一个C#/。NET应用程序,我想实现以下行为:

我有一个弹出菜单。每当用户点击 内的任何 弹出菜单时,我都希望弹出菜单关闭。

但是,每当用户不在应用程序中时,我都不希望发生任何事情。

我正在尝试通过LostFocus事件来管理它,但我无法确定我的应用程序是否是活动窗口。代码看起来像这样。

    private void Button_LostFocus(object sender, System.EventArgs e)
    {
        if (InActiveWindow()) {
           CloseMenu()
        }
        else {
           // not in active window, do nothing
        }
    }

我需要知道的是如何实现InActiveWindow()方法。

3 个答案:

答案 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)

这似乎是最棘手的原因,因为弹出窗口在主窗体停用之前失去焦点,因此活动窗口将始终在此事件发生时位于应用程序中。实际上,您想知道在事件结束后它是否仍然是活动窗口。

你可以设置某种方案,让你记住弹出窗口正在失去焦点,抛弃你需要关闭它的事实,以及在LostFocusDeactivate事件中应用程序的主要表单取消注释,告诉您需要关闭它;但问题是你什么时候处理这​​个音符?

我认为这可能会更容易,至少如果弹出窗口是主窗体的直接子窗口(我怀疑在你的情况下可能是)挂钩Focus或甚至{{1主窗体的事件,如果它是打开的,则使用它关闭弹出窗口(可能通过扫描其实现ICloseOnLostFocus接口的子窗体列表,以便弹出窗口有机会参与决策并执行任何操作否则它需要做。)

我希望我知道一个更好的文档,解释所有这些事件实际上意味着什么,以及它们如何相互排序,MSDN在描述它们时还有很多不足之处。