9

他の子フォーム(mdiではない)を持つWinFormアプリがあります。ユーザーが「Esc」を押すと、フォーカスがなくても一番上のフォームを閉じる必要があります。

キーボードフックを使用してエスケープをグローバルにキャッチできますが、フォームのハンドルも閉じる必要があります。

Win32 APIを使用してそれを行う方法があると思いますが、マネージコードを使用する解決策はありますか?

4

5 に答える 5

7

Win32 を使用する最上位のフォームを取得する 1 つの方法を次に示します (あまりエレガントではありませんが、機能します)。

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;
}
于 2009-06-17T08:34:50.817 に答える
4

Application.Openformsを使用してこれはどうですか

Form GetTopMostForm()
{
    return Application.OpenForms
        .Cast<Form>()
        .First(x => x.Focused);
}
于 2012-02-13T23:40:46.280 に答える
3

これが4年前のスレッドであることは知っていますが、同様の問題があり、他の誰かがこの質問につまずいてWin32呼び出しをいじりたくない場合に備えて、代替ソリューションを思いつきました.

最上位のフォームは、最後にアクティブ化されたフォームになると思います。そのため、Application.OpenForms と同様に、フォームの個別のコレクションを保持できますが、このコレクションは、それぞれが最後にアクティブ化された日時によって並べ替えられます。フォームがアクティブ化されるたびに、コレクションの最初のアイテムに移動します。ESC キーが表示されたら、collection[0] を閉じて削除します。

于 2013-06-07T23:22:54.953 に答える
1

FormCollection は Application オブジェクトによって使用され、OpenForms プロパティを通じてアプリケーションで現在開いているフォームを一覧表示します。

http://msdn.microsoft.com/en-us/library/system.windows.forms.application.openforms.aspxを参照してください。

次に、各フォームの TopMost() プロパティを確認できます。一番上のフォームを見つけたら、それを閉じます。

于 2009-06-16T13:04:40.217 に答える
1

一番上のフォームにシングルトンのようなパターンを実装し、それ自体の 1 つのインスタンスを返す静的プロパティを提供して、単純に閉じることができます。

   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();
于 2009-06-16T15:04:08.150 に答える