为什么WPF中窗口的未加载事件不会触发?

10

在我的WPF应用程序中,我创建了一个窗口并通过调用ShowDialog()方法将其显示为对话框。但是当我使用Close()方法关闭窗口时,该对话框窗口的Unloaded事件未被触发。

MyWindow obj = new MyWindow(); 
obj.ShowDialog();
obj.Close();
3个回答

15

这是一个已知的问题。

使用此代码替代。

   yourWindow.Dispatcher.ShutdownStarted += Dispatcher_ShutdownStarted;

   private void Dispatcher_ShutdownStarted( object sender, EventArgs e )
   {
       //do what you want to do on closing
   }

阅读这里以获取更多详细信息。

编辑

如果上述方法不起作用,请尝试这个。

yourWindow.Closing += new CancelEventHandler(YourWindow_Closing);

void YourWindow_Closing(object sender, CancelEventArgs e)
{

}

1
这个事件在 obj.Close() 后也没有触发。只有当整个应用程序关闭时才会触发。 - HotTester
是的。我已经在对话框窗口的构造函数中创建了 Dispatcher.ShutdownStarted += Dispatcher_ShutdownStarted;,并按照上述方式编写了其事件函数。 - HotTester
1
是的,更新后的答案有效!为此,我们必须使用System.ComponentModel。谢谢 : )。但我仍然想知道为什么Window.Unloaded()或Dispather.ShutdownStarted()没有起作用。这是因为窗口被用作对话框吗? - HotTester
1
我仍然对这种行为感到困惑,但在搜索时,我发现人们建议选择关闭事件以保险起见。在某些情况下,可能会跳过Unloaded事件。目前我仍然不知道为什么。 - Haris Hasan

11

如果您真的想要确认关闭,我认为最好先了解窗口的生命周期和相关事件。

然而,在我看来,最好的确认来源是"Closed"事件。其他框架的方式可能不可靠。

关闭事件

当窗口关闭时,它会触发两个事件:ClosingClosed

Closing在窗口关闭之前被触发,并提供了一个机制来防止窗口关闭。防止窗口关闭的一个常见原因是窗口内容包含已修改的数据。在这种情况下,可以处理Closing事件来确定数据是否有更改,并询问用户是继续关闭窗口而不保存数据还是取消窗口关闭。以下示例显示了处理Closing的关键方面。

此外

Closing事件处理程序会传递一个CancelEventArgs,它实现了BooleanCancel属性,您可以将其设置为true以防止窗口关闭。

如果没有处理Closing,或者处理了但没有被取消,窗口将关闭。在窗口实际关闭之前,Closed会被触发。此时,无法阻止窗口关闭。

注意

虽然窗口可以通过提供在非客户区和客户区的机制来显式关闭,但窗口也可以由应用程序或Windows的其他部分的行为隐式关闭,包括以下内容:

  • 用户注销或关闭Windows。

  • 窗口的所有者关闭。

  • 主应用程序窗口关闭且ShutdownMode为OnMainWindowClose。

  • 调用Shutdown。

所有窗口生命周期事件

下图显示了窗口生命周期中主要事件的顺序。

enter image description here

下图显示了一个未激活的窗口(在窗口显示之前设置ShowActivated为false)生命周期中主要事件的顺序。

enter image description here


0

我偶然发现了这个解决方法。我在我的代码中创建了另一个窗口,因此没有看到 WPF 中未加载事件不触发的问题。

public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();

        new Window(); //<-- this will make Unloaded Event to trigger in WPF
    }
}

这个解决方法在MVVM模式下也适用!

如果你不使用MVVM模式,请忽略下面的代码。

XAML (需要引用System.Windows.Interactivity)

<Window xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">

  <i:Interaction.Triggers>
      <i:EventTrigger EventName="Unloaded">
          <i:InvokeCommandAction Command="{Binding Path=DataContext.WindowUnLoadEventHandler,RelativeSource={RelativeSource AncestorType {x:Type Window}}}"/>
      </i:EventTrigger>
  </i:Interaction.Triggers>
</Window>

代码后台

    public ICommand WindowUnLoadEventHandler
    {
        get
        {
            if (_windowUnload == null)
            {
                _windowUnload = new MyDelegateCommand(ExecuteWindowUnLoadEventHandler);
            }
            return _windowUnload;
        }
    }

    private void ExecuteWindowUnLoadEventHandler(object parameter)
    {
        //Do your thing
    }

我的委托命令

public class MyDelegateCommand : ICommand
{
    private readonly Action<object> _execute;

    public MyDelegateCommand(Action<object> execute)
    {
        this._execute = execute;
    }

    public void Execute(object parameter)
    {
        _execute?.Invoke(parameter);
    }

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public event EventHandler CanExecuteChanged;
}

1
不幸的是,这只能工作,因为创建窗口实例将把它作为应用程序的“打开”窗口添加,因此应用程序将无法正确关闭。 - Martin Zikmund

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接