2010-09-20 28 views
15

Tengo esta situación. Application.OpenForms no devuelve el resultado correcto. es decir, Application.OpenForms.Count = 0 siempre ..Application.OpenForms.Count = 0 siempre

El propósito de obtener el formulario es obtener el propietario del formulario para que pueda pasar el propietario como el parámetro de la función MessageBox.Show().

+0

Proporcione más información. – SLaks

+0

Si consulto Application.OpenForms.Count en form-load, me lo muestra 1. Algo extraño con su aplicación, necesita proporcionar más detalles sobre cómo reproducir el problema. –

+0

Mi aplicación tiene un formulario principal. Aunque tengo el formulario abierto en el momento en que se ejecuta este código, devuelve 0. Gracias Albin, SLaks – Ananth

Respuesta

34

Hay un error en Windows Forms que hace que un formulario desaparezca de la colección Application.OpenForms. Esto sucederá cuando asigne la propiedad ShowInTaskbar, FormBorderStyle, ControlBox, Min/MaximizedBox, RightToLeftLayout, HelpButton, Opacity, TransparencyKey, ShowIcon o MdiParent después de que se haya creado la ventana. Estas propiedades son especiales porque se especifican como indicadores de estilo en la llamada nativa CreateWindowEx(). Esta forma ejemplo muestra el error:

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 deben llamar CreateWindowEx() de nuevo para hacer que la propiedad efectiva cambiado, pasando por diferentes indicadores de estilo. La destrucción de la ventana original primero tiene efectos secundarios más allá del parpadeo muy notable, uno de ellos es que la clase Application pierde la pista de la forma ya que ve desaparecer la ventana. Con el error que no lo vuelve a agregar cuando se crea la nueva ventana. Evite el error estableciendo la propiedad solo en el constructor, el código que se ejecuta antes de que se llame a CreateWindowEx(), y en ningún caso a los controladores.

En general, evite confiar en OpenForms debido a este error. Proporcione a la clase que necesita mostrar el cuadro de mensaje una referencia a la instancia de formulario a través de su constructor. MessageBox generalmente descubre una ventana padre por sí mismo correctamente por cierto, seleccionará la ventana activa y eso es correcto el 99% del tiempo. Si necesita llamar a BeginInvoke() desde un hilo de trabajo, asegúrese de copiar SynchronizationContext.Current en su constructor y llame a su método Post() más adelante. Garantiza que su biblioteca también funcionará con otras bibliotecas de clases de GUI.

+0

MessageBox utiliza el método Win32 API GetActiveWindow que puede devolver una ventana que no pertenece a su aplicación. Es mejor no confiar en esto y siempre especificar la ventana del propietario usted mismo. – Tergiver

+1

@Tergiver: GetActiveWindow solo puede devolver un identificador de ventana para una ventana que se creó en el mismo subproceso. http://msdn.microsoft.com/en-us/library/ms646292%28VS.85%29.aspx –

+0

Tiene razón. Me disculpo, parece que estoy confundiendo mis métodos API. – Tergiver

0

Tuve el problema cuando usé ShowInTaskBar = true. Lo resolví usando Windows API en lugar de las propiedades .Net. Application.OpenForms se mantuvo intacto.

No sé si funciona como una solución general utilizando SetWindowLong para cambiar las propiedades pero funciona para 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); 
    } 
} 
Cuestiones relacionadas