2010-09-20 11 views
15

J'ai cette situation. Application.OpenForms ne retourne pas le bon résultat. c'est-à-dire Application.OpenForms.Count = 0 toujours ..Application.OpenForms.Count = 0 toujours

Le but de l'obtention du formulaire est d'obtenir le propriétaire du formulaire afin que je puisse passer le propriétaire en tant que paramètre de la fonction MessageBox.Show().

+0

Veuillez fournir plus d'informations. – SLaks

+0

Si je vérifie Application.OpenForms.Count dans le formulaire-charge il me montre 1. Quelque chose est étrange avec votre application, vous devez fournir plus de détails sur la façon de reproduire le problème. –

+0

Mon application a une forme principale.Même si j'ai le formulaire ouvert au moment où ce code est exécuté, il renvoie 0. Merci Albin, SLaks – Ananth

Répondre

34

Il existe un bogue dans Windows Forms qui fait disparaître un formulaire de la collection Application.OpenForms. Cela se produit lorsque vous affectez la propriété ShowInTaskbar, FormBorderStyle, ControlBox, Min/MaximizedBox, RightToLeftLayout, HelpButton, Opacité, TransparencyKey, ShowIcon ou MdiParent après la fenêtre a été créée. Ces propriétés sont spéciales en ce sens qu'elles sont spécifiées en tant qu'indicateurs de style dans l'appel natif CreateWindowEx(). Ce formulaire exemple illustre le bogue:

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 Forms doivent appeler CreateWindowEx() pour rendre la propriété effective changé, passant des drapeaux de style différents. Détruire la fenêtre d'origine a d'abord des effets secondaires au-delà du scintillement très perceptible, l'un d'eux est que la classe Application perd la trace du formulaire car il voit la fenêtre disparaître. Avec le bug qu'il ne rajoute pas quand la nouvelle fenêtre est créée. Évitez le bogue en définissant la propriété uniquement dans le constructeur, le code qui s'exécute avant l'appel de CreateWindowEx(), pas dans les gestionnaires d'événements.

En général, évitez de vous fier à OpenForms à cause de ce bogue. Donnez à la classe qui doit afficher la boîte de message une référence à l'instance de formulaire via son constructeur. MessageBox trouve généralement une fenêtre parent par elle-même correctement, il choisira la fenêtre active et c'est correct 99% du temps. Si vous en avez besoin pour appeler BeginInvoke() à partir d'un thread de travail, veillez à copier SynchronizationContext.Current dans votre constructeur et appelez sa méthode Post() plus tard. Garantit que votre bibliothèque fonctionnera également avec d'autres bibliothèques de classes d'interface graphique.

+0

MessageBox utilise la méthode API Win32 GetActiveWindow qui peut renvoyer une fenêtre qui n'appartient pas à votre application. Il est préférable de ne pas compter dessus et de toujours spécifier la fenêtre du propriétaire. – Tergiver

+1

@Tergiver: GetActiveWindow ne peut renvoyer qu'un handle de fenêtre pour une fenêtre créée sur le même thread. http://msdn.microsoft.com/fr-fr/library/ms646292%28VS.85%29.aspx –

+0

Vous avez raison. Je m'excuse, il semble que mes méthodes d'API soient confuses. – Tergiver

0

J'ai rencontré le problème lorsque j'ai utilisé ShowInTaskBar = true. Je l'ai résolu en utilisant l'API Windows au lieu des propriétés .Net. Application.OpenForms est resté intact.

Je ne sais pas si cela fonctionne comme une solution de contournement générale en utilisant SetWindowLong pour modifier les propriétés, mais cela fonctionne pour 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); 
    } 
} 
Questions connexes