简体   繁体   English

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

[英]Determine Whether Program is the Active Window in .NET

I have a C#/.NET app and I want to implement the following behavior: 我有一个C#/。NET应用程序,并且想要实现以下行为:

I have a popup menu. 我有一个弹出菜单。 Whenever the user clicks on anything within the application that is not the popup menu, I want the popup menu to close. 每当在不是弹出菜单中的应用程序内的任何用户点击,我想在弹出菜单中关闭。

However, whenever a user is not in the application I don't want anything to happen. 但是,无论何时用户不在应用程序中,我都不希望发生任何事情。

I'm trying to manage this through the LostFocus event, but I'm having trouble determining whether my application is the active window. 我正在尝试通过LostFocus事件来管理此事件,但是在确定我的应用程序是否为活动窗口时遇到了麻烦。 The code looks something like this. 该代码看起来像这样。

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

What I need to know is how to implement the InActiveWindow() method. 我需要知道的是如何实现InActiveWindow()方法。

You could P/Invoke into GetForegroundWindow() , and compare the HWND returned to the application's form.Handle property. 您可以P / Invoke到GetForegroundWindow()中 ,然后将返回的HWND与应用程序的form.Handle属性进行比较。

Once you have the handle, you can also P/Invoke GetAncestor() to get the root owner window. 拥有句柄后,还可以P /调用GetAncestor()以获取根所有者窗口。 This should be the handle of your application's main, startup window, if this is in your application. 如果它在应用程序中,则它应该是应用程序主启动窗口的句柄。

I stumbled upon your question while working on a project and based on Reed Copsey's answer , I wrote this quick code which seems to do the job well. 在进行项目时,我偶然发现了您的问题,并且根据Reed Copsey的回答 ,我编写了此快速代码,看起来很不错。

Here's the code: 这是代码:

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

I didn't have too much time to convert it to C# as I'm working on a project with a deadline in 2 days but I believe you can quickly do the conversion. 我没有太多时间将其转换为C#,因为我正在进行的项目的截止日期为2天,但是我相信您可以快速进行转换。

Here is the C# version of the VB.NET code: 这是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);
        }
    }
}

It seems like the biggest reason this is tricky is because the popup loses focus before the main form is deactivated, so the active window will always be in the application at the time of this event. 看来这很棘手的最大原因是因为在取消激活主窗体之前弹出窗口失去了焦点,因此活动窗口在此事件发生时始终位于应用程序中。 Really, you want to know whether it will still be the active window after the event is over. 确实,您想知道事件结束后它是否仍然是活动窗口。

You could set up some kind of scheme where you remember that a popup is losing focus, set aside the fact that you will need to close it, and in the LostFocus or Deactivate event of the application's main form cancel the note that tells you you need to close it; 您可以设置某种方案,让您记住弹出窗口失去焦点,抛开您需要关闭它的事实,然后在应用程序主窗体的LostFocusDeactivate事件中取消提示您的注释关闭它; but the problem is when will you process the note? 但问题是您何时会处理笔记?

I'm thinking it might be easier, at least if the popup is a direct child of the main form (which I suspect in your case it may be) to hook the Focus or maybe even Click event of the main form and use it close the popup if it is open (perhaps by scanning its list of child forms for any that implement an ICloseOnLostFocus interface, so that the popup will have a chance to participate in the decision and do anything else it needs to do). 我想这可能会更容易,至少如果弹出窗口是主窗体的直接子代(我怀疑在您的情况下,可能是这样)挂钩主窗体的Focus或什至Click事件并关闭它弹出窗口是否打开(可能通过扫描其子窗体列表来查找实现ICloseOnLostFocus接口的任何弹出窗口,以便该弹出窗口有机会参与决策并执行其需要做的任何其他操作)。

I wish I knew of a better document explaining what all these events actually mean and how they are sequenced with respect to one another, MSDN leaves a lot to be desired in describing them. 我希望我知道有更好的文档来解释所有这些事件的实际含义以及它们之间如何相互排序,MSDN在描述它们时还有很多工作要做。

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

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