2017-05-25 66 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變量。如果你願意,你可以製作這些局部變量。