Определите, является ли программа активным окном в.NET
У меня есть приложение на C#/.NET, и я хочу реализовать следующее поведение:
У меня есть всплывающее меню. Всякий раз, когда пользователь нажимает на что-либо внутри приложения, которое не является всплывающим меню, я хочу закрыть всплывающее меню.
Однако, когда пользователя нет в приложении, я не хочу, чтобы что-то происходило.
Я пытаюсь управлять этим с помощью события LostFocus, но у меня возникают проблемы с определением, является ли мое приложение активным окном. Код выглядит примерно так.
private void Button_LostFocus(object sender, System.EventArgs e)
{
if (InActiveWindow()) {
CloseMenu()
}
else {
// not in active window, do nothing
}
}
Что мне нужно знать, это как реализовать метод InActiveWindow().
3 ответа
Вы можете выполнить P/Invoke в GetForegroundWindow() и сравнить возвращенный HWND со свойством form.Handle приложения.
Если у вас есть дескриптор, вы также можете P/Invoke GetAncestor () получить окно владельца root. Это должен быть дескриптор главного окна вашего приложения, если оно есть в вашем приложении.
Я наткнулся на ваш вопрос, работая над проектом и основываясь на ответе Рида Копси, я написал этот быстрый код, который, кажется, хорошо справляется со своей задачей.
Вот код:
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);
}
}
}
Похоже, самая главная причина, по которой это сложно, заключается в том, что всплывающее окно теряет фокус, прежде чем основная форма будет деактивирована, поэтому активное окно всегда будет в приложении во время этого события. Действительно, вы хотите знать, будет ли оно оставаться активным окном после окончания события.
Вы могли бы создать какую-то схему, где вы помните, что всплывающее окно теряет фокус, откладывая тот факт, что вам нужно будет закрыть его, и в LostFocus
или же Deactivate
событие основной формы приложения отменить заметку, которая говорит вам, что вам нужно закрыть его; но проблема в том, когда вы обработаете заметку?
Я думаю, что это может быть проще, по крайней мере, если всплывающее окно является прямым потомком основной формы (что я подозреваю, что в вашем случае это может быть), чтобы перехватить Focus
или, может быть, даже Click
событие основной формы и использовать его, чтобы закрыть всплывающее окно, если оно открыто (возможно, путем сканирования его списка дочерних форм на наличие тех, которые реализуют интерфейс ICloseOnLostFocus, чтобы у всплывающего окна была возможность участвовать в решении и делать что-либо еще, нужно сделать).
Хотелось бы мне знать о лучшем документе, объясняющем, что на самом деле означают все эти события и как они упорядочены по отношению друг к другу, MSDN оставляет желать лучшего при их описании.