Wie bekomme ich das Handle des obersten Formulars in einer WinForm-App?

Ich habe eine WinForm-App, die andere untergeordnete Formulare hat (nicht MDI). Wenn der Benutzer "Esc" drückt, sollte das oberste Formular geschlossen werden, auch wenn es nicht den Fokus hat.

Ich kann einen Tastaturhaken verwenden, um die Flucht global zu fangen, aber ich muss auch den Griff des Formulars schließen.

Ich denke, es gibt eine Möglichkeit, dies mit der Win32-API zu tun, aber gibt es eine Lösung mit verwaltetem Code?

Antworten auf die Frage(5)

Lösung für das Problem

die oberste Form zu erhalten, die Win32 verwendet (nicht sehr elegant, aber es funktioniert):

<code>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;
}
</code>
 bruestle231. Juli 2018, 21:04
Das Aufrufen von GetNextWindow in einer Schleife kann zu einer Endlosschleife führen. Ich bin mir also nicht sicher, ob diese Lösung die beste ist. Siehe Folgendes: "Die EnumChildWindows-Funktion ist zuverlässiger als der Aufruf von GetWindow in einer Schleife. Eine Anwendung, die GetWindow zur Ausführung dieser Aufgabe aufruft, kann in einer Endlosschleife abgefangen werden oder auf ein Fenster verweisen, das zerstört wurde."pinvoke.net/default.aspx/user32.GetWindow

eren und eine statische Eigenschaft bereitstellen, die die eine Instanz von sich selbst zurückgibt und sie einfach schließt.

<code>   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();
</code>
 Zachary Yates27. Okt. 2011, 06:53
Oh ich verstehe. Wenn Sie "topmost" sagen, meinen Sie die höchste Z-Ordnung, nicht die Spitze der Parent-Child-Formularhierarchie. Es ist ein bisschen verwirrend.
 tzup08. Aug. 2011, 07:18
@ Zachary Yates, die Anforderung ist, dass untergeordnete Formulare geschlossen werden können, nicht das Hauptformular.
 Zachary Yates24. Aug. 2010, 22:26
Ich glaube, Sie haben seine Antwort falsch verstanden. Es ist immer nur ein MainForm geöffnet, oder? Das Singleton-Muster bietet ein statisches Handle für das Formular an einer beliebigen Stelle in der App, einschließlich Ihres Tastatur-Hooks.
 tzup17. Juni 2009, 08:56
Ich denke, dass Sie die Frage falsch verstanden haben. Stellen Sie sich eine WinForm-App vor, bei der ein Hauptformular maximiert und viele andere kleinere Formulare über das Hauptformular kaskadiert werden. Jedes Mal, wenn Sie Esc drücken, sollte das oberste Formular geschlossen werden (denken Sie daran, dass es möglicherweise nicht den Fokus hat). Hoffe das macht die Sache klarer.

um die aktuell geöffneten Formulare in einer Anwendung über die OpenForms-Eigenschaft aufzulisten

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

Dann können Sie die TopMost () -Eigenschaft jedes Formulars überprüfen. Und wenn Sie ein oberstes Formular finden, schließen Sie es.

 tzup17. Juni 2009, 10:11
Leider erhält oder setzt die Form.TopMost-Eigenschaft einen Wert, der angibt, ob das Formular als oberstes Formular angezeigt werden soll. Dies sagt mir nicht, ob das Formular am besten ist.

Wie wäre es damitAnwendung.Openforms

<code>Form GetTopMostForm()
{
    return Application.OpenForms
        .Cast<Form>()
        .First(x => x.Focused);
}
</code>
 tzup20. Feb. 2012, 09:09
Die Anforderung besteht darin, das oberste Formular zu schließen, das möglicherweise nicht den Fokus hat.

dass dies ein 4 Jahre alter Thread ist, aber ich hatte ein ähnliches Problem und fand gerade eine alternative Lösung, nur für den Fall, dass jemand anderes über diese Frage stolpert und nicht mit Win32-Aufrufen herumspielen möchte.

Ich gehe davon aus, dass das oberste Formular das zuletzt aktivierte ist. Sie können also eine separate Sammlung von Formularen aufbewahren, die Application.OpenForms ähnelt, mit der Ausnahme, dass diese Sammlung nach dem Zeitpunkt der letzten Aktivierung sortiert wird. Wenn ein Formular aktiviert ist, verschieben Sie es zum ersten Element der Sammlung. Immer wenn Sie die ESC-Taste sehen, schließen Sie die Sammlung [0] und entfernen sie.

 Boris B.18. Juni 2013, 14:21
Oder verwenden Sie einen Stapel, dies ist natürlicher als eine Sammlung

Ihre Antwort auf die Frage