2010-09-20 45 views
15

我有這種情況。 Application.OpenForms不會返回正確的結果。即Application.OpenForms.Count = 0總是..Application.OpenForms.Count = 0總是

獲取表單的目的是獲取表單的所有者,以便我可以通過所有者作爲MessageBox.Show()函數的參數。

+0

請提供更多信息。 – SLaks 2010-09-20 12:45:02

+0

如果我在表單加載中檢查Application.OpenForms.Count,它會顯示出我1.您的應用程序有些奇怪,您需要提供有關如何重現問題的更多詳細信息。 – 2010-09-20 12:45:34

+0

我的應用程序有一個主窗體。即使我在當代碼執行時打開窗體,它返回0.謝謝Albin,SLaks – Ananth 2010-09-20 12:49:41

回答

34

Windows Forms中存在一個使Application.OpenForms集合中的表單消失的錯誤。當您在創建窗口後分配ShowInTaskbar,FormBorderStyle,ControlBox,Min/MaximizedBox,RightToLeftLayout,HelpButton,Opacity,TransparencyKey,ShowIcon或MdiParent屬性時,會發生這種情況。這些屬性的特殊之處在於它們在本機CreateWindowEx()調用中被指定爲樣式標誌。此示例的形式演示了該bug:

public partial class Form1 : Form { 
    public Form1() { 
     InitializeComponent(); 
     button1.Click += button1_Click; 
    } 
    private void button1_Click(object sender, EventArgs e) { 
     Console.WriteLine(Application.OpenForms.Count); 
     this.ShowInTaskbar = !this.ShowInTaskbar; 
     Console.WriteLine(Application.OpenForms.Count); 
    } 
} 

Windows窗體必須再次調用CreateWindowEx()使改變屬性有效,通過不同風格的標誌。首先銷燬原始窗口的副作用超出了非常明顯的閃爍,其中一個原因是應用程序類由於看到窗口消失而失去跟蹤。有了它在創建新窗口時不會將其添加回來的錯誤。通過僅在構造函數中設置屬性來避免該錯誤,而在調用CreateWindowEx()之前運行的代碼不在任何事件處理程序中。

一般來說,避免依靠OpenForms由於這個錯誤。給需要顯示消息框的類通過其構造函數引用表單實例。 MessageBox通常會自己正確地指出一個父窗口btw,它會選擇活動窗口,並且99%的時間是正確的。如果您需要從工作線程調用BeginInvoke(),那麼一定要複製構造函數中的SynchronizationContext.Current並稍後調用Post()方法。確保您的庫也可以與其他GUI類庫一起工作。

+0

MessageBox使用Win32 API方法GetActiveWindow,它可以返回不屬於您的應用程序的窗口。最好不要依賴這個,並且總是自己指定所有者窗口。 – Tergiver 2010-09-20 13:24:34

+1

@Tergiver:GetActiveWindow只能返回在同一個線程上創建的窗口的窗口句柄。 http://msdn.microsoft.com/en-us/library/ms646292%28VS.85%29.aspx – 2010-09-20 13:28:53

+0

你是對的。我很抱歉,我似乎讓我的API方法感到困惑。 – Tergiver 2010-09-20 13:35:22

0

我在使用ShowInTaskBar = true時遇到了問題。我通過使用Windows API而不是.Net屬性來解決它。 Application.OpenForms保持不變。

我不知道它是否作爲使用SetWindowLong更改屬性的常規解決方法,但適用於ShowInTaskBar = true。

public static class ShowInTaskBar { 

    [DllImport("User32.dll")] 
    private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); 
    [DllImport("User32.dll")] 
    private static extern int GetWindowLong(IntPtr hWnd, int nIndex); 

    [DllImport("user32.dll")] 
    private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); 

    private const int SW_HIDE = 0x00; 
    private const int SW_SHOW = 0x05; 

    private const int WS_EX_APPWINDOW = 0x40000; 
    private const int GWL_EXSTYLE = -0x14; 

    public static void ShowWindowInTaskbar(IntPtr pMainWindow) { 
     SetWindowLong(pMainWindow, GWL_EXSTYLE, GetWindowLong(pMainWindow, GWL_EXSTYLE) | WS_EX_APPWINDOW); 

     ShowWindow(pMainWindow, SW_HIDE); 
     ShowWindow(pMainWindow, SW_SHOW); 
    } 

    public static void HideWindowFromTaskbar(IntPtr pMainWindow) { 
     SetWindowLong(pMainWindow, GWL_EXSTYLE, GetWindowLong(pMainWindow, GWL_EXSTYLE) | ~WS_EX_APPWINDOW); 

     ShowWindow(pMainWindow, SW_HIDE); 
     ShowWindow(pMainWindow, SW_SHOW); 
    } 
}