2009-06-16 97 views
8

我有一個WinForm應用程序有其他子窗體(不是mdi)。如果用戶按下「Esc」,即使沒有焦點,最頂端的表格也應該關閉。如何獲取WinForm應用程序中最頂層窗體的句柄?

我可以使用鍵盤鉤來全局捕捉逃逸,但我也需要關閉窗體的句柄。

我想有一種方法可以做到這一點使用Win32 API,但有沒有使用託管代碼的解決方案?

回答

7

這裏是讓使用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; 
} 
1

的FormCollection是由應用程序對象通過OpenForms屬性列出在應用程序中當前打開的形式

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

然後,你可以檢查每一個最頂層的形式()屬性。當你找到最頂層的表單時,你可以關閉它。

+2

不幸的是,Form.TopMost屬性獲取或設置一個值,該值指示窗體是否應顯示爲最頂層窗體。這並不能告訴我表單是否最重要。 – tzup 2009-06-17 08:11:56

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(); 
+0

我認爲你誤解了這個問題。設想一個WinForm應用程序,其中一個主窗體最大化,許多其他更小的窗體在主窗體上級聯。每次擊中Esc時,最上面的表格都應該關閉(請記住它可能沒有焦點)。希望這可以讓事情更清楚。 – tzup 2009-06-17 06:56:39

+0

我想你可能誤解了他的回答。一次只能打開一個MainForm,對吧?單例模式從應用程序中的任何位置向表單提供靜態句柄,包括鍵盤鉤子。 – 2010-08-24 20:26:03

+0

@Zachary耶茨,要求是能夠關閉兒童表格,而不是主要形式。 – tzup 2011-08-08 05:18:01

3

這樣如何使用Application.Openforms

Form GetTopMostForm() 
{ 
    return Application.OpenForms 
     .Cast<Form>() 
     .First(x => x.Focused); 
} 
2

我知道這是一個4歲的線程,但我有一個類似的問題,只是想出了一個替代解決方案,以防其他人絆倒在這個問題上,不想搞亂Win32調用。

我假設最上面的窗體將是上次激活的窗體。所以你可以保留一個單獨的表單集合,類似於Application.OpenForms,除了這個集合將在每個上次被激活時排序。每當表單被激活時,將其移動到集合的第一個項目。每當看到ESC鍵時,您都會關閉收集[0]並將其刪除。