Reputation: 11963
I ran into a weird case where Close
event of the child window propagate to the parent window and causes it to close as well.
I made a minimum example as shown below
For TestWindow
there is nothing but the default WPF window generated by VS
and in App.xaml.cs
I override the OnStartup
event and use it as a custom Main
function
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
TestWindow t = new TestWindow();
t.ShowDialog();
}
Now if you click on the X button to close TestWindow, the application shuts down instead of showing the MainWindow
. If you comment out t.ShowDialog
then the MainWindow
will show just fine. Next if you listen to the Closing
event of MainWindow
you will find that it will trigger after the TestWindow
closes which doesn't seem right to me
Upvotes: 4
Views: 644
Reputation:
It's not actually propagating, WPF runs your first dialog and upon closing notices that the process has no further windows present. WPF posts an application quit message for later processing. In the meantime your code has proceeded to display a further window which when processing the message pump encounters the quit message and so closes the window and terminates your app.
Debug log:
Information: 0 : App OnStartup
Information: 0 : new MainWindow
Information: 0 : MainWindow closing
Information: 0 : App exiting
To resolve, you need to remove the StartupUri
and instead handle the Startup
event.
Change:
<Application x:Class="WpfCloseProblem.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfCloseProblem"
StartupUri="MainWindow.xaml"> ...
...to:
<Application x:Class="WpfCloseProblem.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfCloseProblem"
Startup="Application_Startup">
Then discard the code on OnStartup and instead define a handler for Startup:
//protected override void OnStartup(StartupEventArgs e)
//{
// base.OnStartup(e);
//
// TestWindow t = new TestWindow();
// t.ShowDialog();
//}
private void Application_Startup(object sender, StartupEventArgs e)
{
var main = new MainWindow();
TestWindow t = new TestWindow();
t.ShowDialog();
main.Show();
}
Previously I was able to confirm that after the dialog closed, MainWindow
was created; loaded and closed in quick succession.
Upvotes: 4
Reputation: 63317
The way App
works here is it chooses the first started window as the main window. So in your case, the TestWindow
will be chosen as the main window. The ShutdownMode
in your code is somehow set to OnMainWindowClose
. So after closing TestWindow
, all child windows (including your MainWindow
) have their Closing
fired.
So the problem here is not propagating up, but propagating down the closing event.
You should not create any window before your main window actually being started first. Or if you want, you can set ShutdownMode
to OnLastWindowClose
.
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
Application.Current.ShutdownMode = ShutdownMode.OnLastWindowClose;
TestWindow t = new TestWindow();
t.ShowDialog();
}
Or you can set the MainWindow
explicitly in the constructor of your main window:
public MainWindow(){
InitializeComponent();
Application.Current.MainWindow = this;
}
However if using ShowDialog()
, there is no way for you to set the MainWindow
explicitly. Because right after closing the TestWindow
(at that time it's still main window), the whole app will be shutdown.
Edit: I don't find any reference about this but it can be checked and we can be sure about that, here is the debugging:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
new TestWindow();//not even need to be shown
var wm = Application.Current.MainWindow;// points to the new TestWindow
//If there is not any Window init here, the MainWindow is just null
}
Upvotes: 3