C# Application.OpenForms.Count始终为0

C# Application.OpenForms.Count始终为0,c#,.net,winforms,C#,.net,Winforms,我有这种情况。 Application.OpenForms不会返回正确的结果。ieApplication.OpenForms.Count=0始终 获取表单的目的是获取表单的所有者,以便我可以将所有者作为MessageBox.Show()函数的参数传递 Windows窗体中存在一个错误,该错误使窗体从Application.OpenForms集合中消失。创建窗口后,当您指定ShowInTaskbar、FormBorderStyle、ControlBox、Min/MaximizedBox、Right

我有这种情况。 Application.OpenForms不会返回正确的结果。ie
Application.OpenForms.Count=0
始终


获取表单的目的是获取表单的所有者,以便我可以将所有者作为
MessageBox.Show()函数的参数传递

Windows窗体中存在一个错误,该错误使窗体从Application.OpenForms集合中消失。创建窗口后,当您指定ShowInTaskbar、FormBorderStyle、ControlBox、Min/MaximizedBox、RightToLeftLayout、HelpButton、Opacity、TransparencyKey、ShowIcon或MdiParent属性时,会发生这种情况。这些属性的特殊之处在于它们在本机CreateWindowEx()调用中被指定为样式标志。此示例表单演示了错误:

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通常自己正确地计算出父窗口。顺便说一句,它会选择活动窗口,并且99%的时间都是正确的。如果需要它从工作线程调用BeginInvoke(),请确保复制构造函数中的SynchronizationContext.Current并稍后调用其Post()方法。确保您的库也可以与其他GUI类库一起使用。

我在使用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);
    }
}

请提供更多信息。如果我在表单加载中检查Application.OpenForms.Count,它会显示1。您的应用程序有些奇怪,您需要提供有关如何重现问题的更多详细信息。我的应用程序有一个主窗体。即使在执行此代码时打开了窗体,它仍返回0。感谢Albin,Slaks您使用的是Windows应用程序还是WPF应用程序,我可以知道吗?Windows应用程序感谢SivaMessageBox使用Win32 API方法GetActiveWindow,它可以返回不属于您的应用程序的窗口。最好不要依赖于此,始终自己指定所有者窗口。@Tergiver:GetActiveWindow只能为在同一线程上创建的窗口返回窗口句柄。你说得对。很抱歉,我似乎把API方法弄糊涂了。我在迁移到VB.NET的VB6应用程序中遇到了这个问题。在我的例子中,它没有分配给任何指定的属性,但它导致在窗体生命周期的早期创建窗口句柄,因为VB6代码中带有API调用。将API调用延迟到在正常事件过程中创建窗口句柄之后,可以避免此问题。@HansPassant您能给我一些建议吗。这个问题已经显现出来了,因为我必须允许用户更改应用程序MDI表单的布局——当这种情况发生时,上面的内容就会显现出来。我可以捕捉到这样一个事实,即集合为零,只显示按摩盒而没有父对象-但是有没有其他方法来获取活动表单句柄?它确实会使表单显示并隐藏在任务栏中,但它也会使我的表单窗口不可见,我无法再次使其可见。