Определите, является ли программа активным окном в .NET - PullRequest
3 голосов
/ 21 мая 2009

У меня есть приложение C # / .NET, и я хочу реализовать следующее поведение:

У меня есть всплывающее меню. Всякий раз, когда пользователь нажимает на что-либо в приложении, которое является , а не всплывающим меню, я хочу закрыть всплывающее меню.

Однако, когда пользователя нет в приложении, я не хочу, чтобы что-то происходило.

Я пытаюсь управлять этим с помощью события LostFocus, но у меня возникают проблемы с определением, является ли мое приложение активным окном. Код выглядит примерно так.

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

Что мне нужно знать, это как реализовать метод InActiveWindow ().

Ответы [ 3 ]

4 голосов
/ 21 мая 2009

Вы можете выполнить P / Invoke в GetForegroundWindow () и сравнить HWND, возвращенное свойству form.Handle приложения.

Получив дескриптор, вы также можете P / Invoke GetAncestor () , чтобы получить окно владельца root. Это должен быть дескриптор главного окна вашего приложения, если оно есть в вашем приложении.

2 голосов
/ 01 января 2011

Я наткнулся на ваш вопрос, работая над проектом и основываясь на ответе Рида Копси , я написал этот быстрый код, который, кажется, хорошо справляется с работой.

Вот код:

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);
        }
    }
}
1 голос
/ 24 июня 2009

Кажется, что самая большая причина, по которой это сложно, состоит в том, что всплывающее окно теряет фокус, прежде чем основная форма деактивируется, поэтому активное окно всегда будет в приложении во время этого события. Действительно, вы хотите знать, будет ли оно оставаться активным окном после окончания события.

Вы можете установить какую-то схему, в которой вы помните, что всплывающее окно теряет фокус, откладывая тот факт, что вам нужно будет его закрыть, и в случае события LostFocus или Deactivate основной формы приложения отмените записка, которая говорит вам, что вам нужно закрыть ее; но проблема в том, когда вы обработаете заметку?

Я думаю, что может быть проще, по крайней мере, если всплывающее окно является прямым потомком основной формы (что, я подозреваю, в вашем случае может быть) перехватить событие Focus или, возможно, даже Click основной формы и используйте ее, чтобы закрыть всплывающее окно, если оно открыто (возможно, путем сканирования его списка дочерних форм на наличие тех, которые реализуют интерфейс ICloseOnLostFocus, так что у всплывающего окна будет возможность участвовать в принятии решения и делать все, что ему нужно делает).

Хотелось бы, чтобы я знал о лучшем документе, объясняющем, что на самом деле означают все эти события и как они упорядочены по отношению друг к другу, MSDN оставляет желать лучшего при их описании.

...