Как получить дескриптор самой верхней формы в приложении WinForm? - PullRequest
8 голосов
/ 16 июня 2009

У меня есть приложение WinForm, которое имеет другие дочерние формы (не mdi). Если пользователь нажимает «Esc», верхняя форма должна быть закрыта, даже если она не имеет фокуса.

Я могу использовать клавиатуру, чтобы поймать Escape, но мне нужно, чтобы ручка формы была закрыта.

Я думаю, что есть способ сделать это с помощью Win32 API, но есть ли решение с использованием управляемого кода?

Ответы [ 5 ]

7 голосов
/ 17 июня 2009

Вот один из способов получить верхнюю форму, которая использует Win32 (не очень элегантно, но работает):

public const int GW_HWNDNEXT = 2; // The next window is below the specified window
public const int GW_HWNDPREV = 3; // The previous window is above

[DllImport("user32.dll")]
static extern IntPtr GetTopWindow(IntPtr hWnd);

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsWindowVisible(IntPtr hWnd);

[DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "GetWindow", SetLastError = true)]
public static extern IntPtr GetNextWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.U4)] int wFlag);

/// <summary>
/// Searches for the topmost visible form of your app in all the forms opened in the current Windows session.
/// </summary>
/// <param name="hWnd_mainFrm">Handle of the main form</param>
/// <returns>The Form that is currently TopMost, or null</returns>
public static Form GetTopMostWindow(IntPtr hWnd_mainFrm)
{
    Form frm = null;

    IntPtr hwnd = GetTopWindow((IntPtr)null);
    if (hwnd != IntPtr.Zero)
    {
        while ((!IsWindowVisible(hwnd) || frm == null) && hwnd != hWnd_mainFrm)
        {
            // Get next window under the current handler
            hwnd = GetNextWindow(hwnd, GW_HWNDNEXT);

            try
            {
                frm = (Form)Form.FromHandle(hwnd);
            }
            catch
            {
                // Weird behaviour: In some cases, trying to cast to a Form a handle of an object 
                // that isn't a form will just return null. In other cases, will throw an exception.
            }
        }
    }

    return frm;
}
3 голосов
/ 08 июня 2013

Я знаю, что это 4-летний поток, но у меня была похожая проблема, и я просто нашел альтернативное решение на тот случай, если кто-нибудь еще наткнется на этот вопрос и не хочет возиться с вызовами Win32. *

Я предполагаю, что самая верхняя форма будет последней активированной. Таким образом, вы можете хранить отдельную коллекцию форм, аналогичную Application.OpenForms, за исключением того, что эта коллекция будет упорядочена после последней активации каждой из них. Всякий раз, когда форма активирована, перемещайте ее к первому элементу коллекции. Всякий раз, когда вы видите клавишу ESC, вы закрываете collection [0] и удаляете его.

3 голосов
/ 14 февраля 2012

Как насчет этого, используя Application.Openforms

Form GetTopMostForm()
{
    return Application.OpenForms
        .Cast<Form>()
        .First(x => x.Focused);
}
1 голос
/ 16 июня 2009

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

   public class MainForm : Form
   {
      private static MainForm mainForm;

      public static MainForm { get { return mainForm; } }

      public MainForm()
      {
         mainForm = this;
      }
   }


   // When the ESC key is pressed...
   MainForm.MainForm.Close();
1 голос
/ 16 июня 2009

FormCollection используется объектом Application для вывода списка открытых в настоящее время форм в приложении через свойство OpenForms

См. http://msdn.microsoft.com/en-us/library/system.windows.forms.application.openforms.aspx

Тогда вы можете проверить свойство TopMost () каждой формы. И когда вы найдете верхнюю форму, вы закрываете ее.

...