为什么Window.Close事件会传播?

时间:2015-10-10 00:32:07

标签: c# wpf

我遇到了一个奇怪的情况,其中子窗口的Close事件传播到父窗口并导致它也关闭。

我做了一个最小的例子,如下所示

对于TestWindow,只有VS

生成的默认WPF窗口

并在App.xaml.cs中覆盖OnStartup事件并将其用作自定义Main函数

protected override void OnStartup(StartupEventArgs e)
{
    base.OnStartup(e);

    TestWindow t = new TestWindow();
    t.ShowDialog();
}

现在,如果您单击X按钮关闭TestWindow,应用程序将关闭而不是显示MainWindow。如果您发表评论t.ShowDialog,则MainWindow会显示正常。接下来,如果您收听Closing MainWindow事件,您会发现它会在TestWindow关闭后触发,这似乎对我不合适

2 个答案:

答案 0 :(得分:4)

它实际上并不是传播,WPF会运行您的第一个对话框,并在关闭时注意到该进程没有其他窗口存在。 WPF发布应用程序退出消息以供稍后处理。与此同时,您的代码已经继续显示另一个窗口,当处理消息时泵会遇到退出消息,因此关闭窗口并终止您的应用程序。

调试日志:

  

信息:0:App OnStartup

     

信息:0:新的MainWindow

     

信息:0:MainWindow关闭

     

信息:0:应用程序退出

要解决此问题,您需要删除StartupUri,然后处理Startup事件。

变化:

<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"> ...

...为:

<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">

然后丢弃OnStartup上的代码,而是为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();
}

以前我能确认对话框关闭后,MainWindow已创建;快速连续装载和关闭。

答案 1 :(得分:3)

App的工作方式是选择第一个启动的窗口作为主窗口。因此,在您的情况下,TestWindow将被选为主窗口。代码中的ShutdownMode以某种方式设置为OnMainWindowClose。因此,在关闭TestWindow后,所有子窗口(包括您的MainWindow)都会Closing被解雇。

所以这里的问题不是传播,而是传播 down 结束事件。

在实际首先启动主窗口之前,不应创建任何窗口。或者,如果您愿意,可以将ShutdownMode设置为OnLastWindowClose

protected override void OnStartup(StartupEventArgs e)
{
  base.OnStartup(e);
  Application.Current.ShutdownMode = ShutdownMode.OnLastWindowClose;
  TestWindow t = new TestWindow();
  t.ShowDialog();
}

或者您可以在主窗口的构造函数中明确设置MainWindow

public MainWindow(){ 
  InitializeComponent();
  Application.Current.MainWindow = this;
}

但是,如果使用ShowDialog(),则无法明确设置MainWindow。因为在关闭TestWindow之后(当时它仍然是主窗口),整个应用程序将被关闭。

修改: 我没有找到任何关于此的参考,但可以检查,我们可以确定,这是调试:

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      
}