[英]WPF application exits immediately when showing a dialog before startup
更新 : 我想,我需要了解在WPF中應用程序啟動之前顯示對話框的“正確”,“支持”方式是什么。
這是代碼:
public partial class App : Application
{
[STAThread]
public static void Main()
{
var app = new App();
app.InitializeComponent();
new DialogWindow().ShowDialog();
app.Run( new MainWindow() );
}
}
DialogWindow
按預期顯示。
但關閉后,應用程序立即退出。 MainWindow
根本不顯示!
我做了一些調試並將問題追溯到:
app
的MainWindow,因為此時沒有MainWindow。 ShutdownCallback
。 app.Run
,隊列中的第一件事就是ShutdownCallback
,這自然會導致應用程序立即關閉。 鑒於此分析,有一個明顯的解決方法:在App
之后創建MainWindow
,從而使其成為app
的MainWindow,這將阻止DialogWindow
導致應用程序關閉。
然而 ,這是困擾我的。
首先,這看起來像是一個骯臟的黑客。 我的意思是,沒有明確的理由按此順序創建窗口,我只通過一些調試找到了這個。 這不是受支持的方式。
其次,這顯然是一個錯誤。 我的意思是,如果顯式不支持在關閉后創建第二個窗口,它應該拋出一些InvalidOperationException
,對吧?
第三,這不僅是一個錯誤,而且看起來像一個非常天真的錯誤,就像多線程初學者會創造的那樣。
所有這些讓我相信 ,也許我沒有得到一些基本的東西? 也許我根本沒有意義? 也許這一切都應該以某種不同的方式完成?
這是一些背景知識:
應用程序必須在啟動時進行一些引導。 檢查這一點,設置異常處理程序,記錄 - 你知道,通常的東西。 在此過程中,可能需要向用戶請求幫助 - 這是對話框的用途。
我絕對不想把所有這些都放在MainWindow.IsVisibleChanged
上執行的某種狀態機上。 我想保持它非常簡單,簡潔和直接 - 引導代碼應該是這樣的方式,這樣就可以很容易地用肉眼發現錯誤。
默認情況下,WPF應用程序的ShutdownMode是OnLastWindowClose。 在您的代碼中,您將顯示一個窗口,然后將其關閉。 因此,最后一個窗口關閉,應用程序關閉。 然后在關閉時,顯示另一個窗口。 由於應用程序正在關閉,窗口立即關閉。
所以一切都按照您的設計和編程工作。
但是,您想要做一些不同的事情:首先顯示為唯一窗口的窗口應該是一個“特殊窗口”,關閉后您想要繼續執行,顯示“主窗口”然后退出應用程序一次它(或與應用程序關聯的所有窗口)關閉。
最簡單的方法:首先將關閉模式設置為OnExplicitShutdown,然后在顯示主窗口后將其設置為OnLastWindowClose或OnMainWindowClose。 在代碼中:
public static void Main()
{
var app = new App();
app.InitializeComponent();
app.ShutdownMode = ShutdownMode.OnExplicitShutdown;
new DialogWindow().ShowDialog();
var mainWindow = new MainWindow();
app.MainWindow = mainWindow;
app.Run(mainWindow);
// When the window has loaded, it should then set the app.ShutdownMode to what you actually want.
}
編輯:我不確定你到底在做什么。 您提供的代碼將無法編譯,因為在正確使用WPF應用程序類(使用App.xaml構建操作作為ApplicationDefinition)時,已經定義了Main方法。 如果您只有一個派生自Application的類,則沒有InitializeComponent()方法。 讓代碼編譯的唯一方法是手動將構建操作更改為Page。 但是,在這種情況下,Application.Current == app。
那么會發生以下情況:
app.Run(new DialogWindow()); app.Run(new MainWindow());
app.Run(new DialogWindow()); app.Run(new MainWindow());
,在創建MainWindow時會出現異常,因為在這種情況下,調度程序循環正常運行。 因此,它實際上可以自行關閉,因此在創建MainWindow時,它會拋出異常,因為調度程序循環已經關閉。 所以再一次,沒有錯誤。
因此,解決此問題的一種方法是更改為OnExplicitShutdown。 然后在步驟4中,沒有達到關閉的理由。 更好(正如更像普通的WPF應用程序)將具有適當的ApplicationDefinition。 從App.xaml中刪除StartupUri,而不是處理Startup事件:
private void OnStartup(object sender, StartupEventArgs e)
{
this.ShutdownMode = ShutdownMode.OnExplicitShutdown;
new DialogWindow().ShowDialog();
var mainWindow = new MainWindow();
this.ShutdownMode = ShutdownMode.OnLastWindowClose; // or OnMainWindowClose
mainWindow.Show();
}
由於在關閉對話框窗口時我們有OnExplicitShudown,因此應用程序沒有理由在此時開始關閉。 然后,在創建MainWindow之后,我們再次將窗口作為主窗口和(一個)應用程序窗口。 那么我們就可以切換到我們想要的關機模式並顯示主窗口。
它似乎有點兒。
我通常不在Main()
放任何東西,我讓no-arg app.Run()
被調用並在OnStartup
方法中調用我需要的所有內容,但這不會改變你所看到的行為。
每當我需要在我的主應用程序窗口准備好顯示之前顯示某些內容時,例如收集輸入或顯示啟動畫面,我會在第二個線程上執行此操作。
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
// show splash
var thread = new Thread(() =>
{
Dispatcher.CurrentDispatcher.BeginInvoke
((Action)(() => new MySplashWindow().Show()));
Dispatcher.Run();
}
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Start();
// run configuration steps
// instantiate and show main window
}
顯然,如果你在第二個線程上調用ShowDialog()
,你需要確保在顯示主窗口之前得到答案。 它的優勢在於,您可以在等待特定部分的用戶輸入時運行其他引導任務; 這實際上取決於你的各種任務的順序。
也許這對你的情況有幫助; 也許不是 - 只是一個想法。
如果將Application.ShutdownMode設置為OnExplicitShutdown
,您是否可以避免將ShutdownCallback置於調度程序隊列中並繼續執行您想要的操作而不考慮Windows? 我沒有測試過這個,但它似乎是一個潛在的解決方案,以及使用Application.MainWindow屬性,可以動態更改。
非常翔實的帖子,感謝所有貢獻。 我使用安慰劑窗口將其設置為主窗口但未顯示。 我還將關閉模式設置為OnLastWindow在打開和關閉所有設置對話框之后,我用實際主窗口替換了安慰劑窗口並調用了App.Run()。 這可能不是最佳實踐,但它有效且工作速度快。
Application app = new App();
MainWindow y = new MainWindow();
app.MainWindow = y;
y.WindowStartupLocation = WindowStartupLocation.CenterScreen;
app.ShutdownMode = ShutdownMode.OnLastWindowClose;
//do lots of setup work to include authentication
MainWindow x = new MainWindow(containerdata)
app.MainWindow = x;
App.Run()
我有類似的問題。 我花了很多時間而無法解決它。 我沒時間了。
我不知道這是一個正確的解決方案,但我只是隱藏了登錄對話框而不是關閉它。 它仍然有效
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.