2017-05-25 63 views
1

我已经看到很多像这样的问题,但我一直遇到一个异常。我试图初始化一些表单,用主窗体调用Application.Run(...)而不显示任何非主窗体,做一些工作,然后动态地显示/隐藏其余窗体。一些虚拟代码如下。在Application.Run()后显示表单()

public static void Main() { 
    MainForm = new DebugUserInterface(); // just a dummy form 
    SubForm = new DebugUserInterface(); // ditto 

    Task.Run((Action) DoWork); // schedule some work on another thread 
    Application.Run(MainForm); // start the message pump 
} 

private static void DoWork() { 
    Thread.Sleep(1000); // pretend to do some work 
    SubForm.Invoke((Action) SubForm.Show); // show the other form 
              // should occur after the message pump has started 
} 

子窗体从不显示。有趣的是,如果我在启动消息泵之前调用SubForm.Show(),则子窗体仅显示并且行为正确,但我希望某些窗体保持不可见,未初始化或甚至不存在(如果我想在运行时创建窗体)在致电Application.Run(...)之前。

我正在使用Mono 5.0.0.100 for macOS来编译此代码并测试运行macOS(使用Mono运行时和Wine)和Windows(使用.NET运行时)上的代码。

+2

至少在Windows上,也可能在Mono上,表单不会被提交给任何特定的线程,直到其本地窗口被创建。而Invoke()不会做你希望它发生的事情。本地窗口创建的时间越晚越好,这就是为什么你需要Show()。您可以将'this.CreateHandle();'附加到窗体构造函数,以强制它更早完成。 –

+0

你应该写这个答案,因为它解决了这个问题。谢谢! –

回答

1

Hans's comment是准确的,但恕我直言引导你走错了路。确实,您不能使用SubForm对象返回正确的线程,因为它的句柄尚未创建。但是你有另外一个对象确实有一个有效句柄:MainForm对象。

此外,您可以使用Form.Shown事件来确保您的代码不会执行,直到显示MainForm(并且特别是具有有效的句柄)。最后,如果你利用新的范例,你可以完全避免显式调用。该框架将为你做。

把那一起,它可能是这个样子:

public static void Main() { 
    MainForm = new DebugUserInterface(); // just a dummy form 
    SubForm = new DebugUserInterface(); // ditto 

    MainForm.Shown += async (sender, e) => 
    { 
     await Task.Run(DoWork); 
     SubForm.Show(); 
    }; 

    Application.Run(MainForm); // start the message pump 
} 

private static void DoWork() { 
    Thread.Sleep(1000); // pretend to do some work 
} 

需要注意的是上述,使用事件处理程序的匿名方法,你甚至不需要为MainForm静态字段和SubForm变量。如果你愿意,你可以制作这些局部变量。