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

发布于 2024-07-22 04:35:43 字数 488 浏览 13 评论 0原文

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

我有一个弹出菜单。 每当用户单击应用程序内的任何内容(不是弹出菜单)时,我都希望关闭弹出菜单。

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

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

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

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

I have a C#/.NET app and I want to implement the following behavior:

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. 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

心碎的声音 2024-07-29 04:35:43

您可以 P/Invoke 到 GetForegroundWindow() ,并比较返回到应用程序的 form.Handle 属性的 HWND。

获得句柄后,您还可以 P/Invoke GetAncestor () 获取根所有者窗口。 如果它在您的应用程序中,这应该是您的应用程序的主启动窗口的句柄。

You could P/Invoke into GetForegroundWindow(), and compare the HWND returned to the application's form.Handle property.

Once you have the handle, you can also P/Invoke GetAncestor() to get the root owner window. This should be the handle of your application's main, startup window, if this is in your application.

小姐丶请自重 2024-07-29 04:35:43

我在开发一个项目时偶然发现了你的问题,并且基于 Reed Copsey 的回答,我编写了这段快速代码,看起来效果很好。

这是代码:

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 天,但我相信您可以快速完成转换。

这是 C# 版本VB.NET 代码:

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

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.

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.

Here is the C# version of the VB.NET code:

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);
        }
    }
}
失退 2024-07-29 04:35:43

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

您可以设置某种方案,让您记住弹出窗口正在失去焦点,忽略您需要关闭它的事实,然后在 LostFocusDeactivate 中应用程序主窗体的事件取消告诉您需要关闭它的注释; 但问题是你什么时候处理这​​张纸条?

我认为这可能会更容易,至少如果弹出窗口是主窗体的直接子窗体(我怀疑在您的情况下可能是这样)来挂钩 Focus 甚至可能 主窗体的 Click 事件并使用它关闭弹出窗口(如果弹出窗口打开)(也许通过扫描其子窗体列表以查找任何实现 ICloseOnLostFocus 接口的窗体,以便弹出窗口有机会参与决策并做任何其他需要做的事情)。

我希望我知道一份更好的文档来解释所有这些事件的实际含义以及它们如何相互排序,MSDN 在描述它们方面还有很多不足之处。

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; 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).

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文