UWP在桌面上被顶部X按钮关闭-无事件

22

一款在桌面上运行的UWP应用程序可以通过顶部的关闭按钮关闭,但它没有任何事件来响应。众所周知,在手机和平板电脑上,无论如何触发,应用程序都应该依赖于Suspending事件,然后应用程序应该依赖于ApplicationExecutionState

然而,这里有一个(可能)常见的情况:在手机上,Suspending事件就足够了,在进行VoIP通话时,操作系统会在应用程序挂起后操作它。 在桌面上使用者期望通过关闭按钮完全关闭应用程序。 因此,如果正在进行电话通话,则应挂断电话并释放某些资源。

如果(仅当)UWP应用程序在桌面上运行时,我如何知道用户何时单击了“关闭”按钮?

5个回答

26

在Windows 10版本1703(Build 10.0.15063)中添加了一个名为“confirmAppClose”的受限制的功能,以便为应用程序提供拦截窗口关闭的能力。

清单命名空间:

xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"

清单:

<Capabilities> 
  <Capability Name="internetClient" /> 
  <rescap:Capability Name="confirmAppClose"/> 
</Capabilities> 

提交到商店时需要额外审批。但是之后会在 SystemNavigationManagerPreview 实例上触发 CloseRequested 事件。

代码:

    public MainPage()
    {
        this.InitializeComponent();
        SystemNavigationManagerPreview.GetForCurrentView().CloseRequested += this.OnCloseRequest;
    }

    private void OnCloseRequest(object sender, SystemNavigationCloseRequestedPreviewEventArgs e)
    {
        if (!saved) { e.Handled = true; SomePromptFunction(); }
    }

您可以延迟执行某些工作 (保存或提示),或者通过将 Handled 设置为 true 来防止窗口关闭 (用户取消提示)。


我看了你分享的链接中的文档页面,但我仍然不知道如何做。你能指导我如何在我的窗口中注册事件处理程序吗? - kkica
1
这里有人发布了一篇关于它的博客:http://codeworks.it/blog/?tag=systemnavigationmanagerpreview - Michael Hawker - MSFT
1
有趣的是,Intellisense在appxmanifest中显示rescap:Capabilty节点,并用波浪线下划线表示该功能不存在,但是添加此功能后,代码可以编译并且该功能变为活动状态。 - zax
1
@zax 我不确定为什么VS无法找出这些部分,但这也是他们在Package上拥有IgnorableNamespaces标签的原因。您可以在那里添加rescap以删除波浪线。 - Michael Hawker - MSFT
1
@MichaelHawker-MSFT,在 IgnorableNamespaces 添加 rescap 后,波浪线和相关的弹出式错误文本仍然存在。VS 2017,15.8.4。 - zax
嗯,我会在VS反馈工具中记录一个问题。 - Michael Hawker - MSFT

4

根据官方关于应用程序生命周期的页面:

没有特别的事件可以表明用户关闭了应用程序。

当用户通过Windows关闭应用程序时和自行关闭应用程序时,关闭行为不同:如果你的应用程序在被用户关闭和被Windows关闭时需要执行不同的操作,你可以使用激活事件处理程序来确定应用程序是被用户终止还是被Windows终止。

因此根据以上内容,在应用程序关闭之前并没有明显的方法可以知道用户是否关闭了应用程序,只有在重新启动后才能知道。真遗憾。


我猜关闭事件不被触发也有道理。如果在窗口关闭后重新打开另一个窗口会怎样?这可行吗?也许吧。 - Hiro
@Hiro,我不确定你所说的“在关闭时重新打开另一个窗口”的意思。无论如何,需求因情况而异,因此有时候可能需要一个Closed事件,有时候则可以忽略它。WinForms和WPF都有这个事件。 - tomab
1
这已经过时了,我在下面发布了一个更新的答案。 - Michael Hawker - MSFT

2
这段代码可以帮助你 -
App.xaml.cs 文件中:
...
using Windows.ApplicationModel;
...

public App()
{
    InitializeComponent();            
    this.Suspending += OnSuspending;
}
...
private void OnSuspending(object sender, SuspendingEventArgs e)
{
    var deferral = e.SuspendingOperation.GetDeferral();
    //Add your logic here, if any
    deferral.Complete();
}

感谢您的选择!!!

1

我删除了原始答案,其中包含Window.Current.Closed事件,因为如果您只有一个窗口实例,则似乎不起作用。还有CoreApplication.Exiting,但根据this主题的判断,它也不起作用。似乎是已知问题,可能会在未来得到解决。最后,似乎没有明确的方法可以确定应用程序何时关闭,只有在暂停时才能确定。

然而,当应用程序关闭时,Window.Current会触发VisibilityChanged事件。问题是,它也会在应用程序最小化和其他一些情况下触发。但我认为与Suspending结合使用,您可以(或多或少地)安全地确定桌面应用程序正在关闭。好消息是,在Suspending之前触发了VisibilityChanged,您可以保存它的值并在OnSuspending处理程序中检查它,之后决定是否需要进行任何清理或其他工作。

但是VisibilityChanged事件在操作系统关闭应用程序时也会被触发。因此,在操作系统关闭和用户关闭之间没有区别。 - tomab
是的,操作系统也可以关闭应用程序,但只有在需要释放资源时才会这样做,这在桌面上可能是相当罕见的情况。无论如何,正如我之前指出的那样 - 看起来没有明确的方法来确定用户何时关闭应用程序。 - Andrei Ashikhmin
如果我们在收到“VisibilityChanged”事件后紧接着收到“Suspending”事件,那么我们可以猜测应用程序已经关闭。但是,如果用户将应用程序最小化,稍后Windows决定暂停我们的应用程序,这种情况不会自然发生吗?那么我们就会错误地猜测应用程序正在关闭,因为用户稍后可以将其最大化并恢复使用。 - Felix
是的,在这种情况下,我们的猜测很可能是不正确的。正如我之前提到的,似乎没有明确的方法来确定应用程序是否被用户关闭,除非你在下一次启动时进行检查。 - Andrei Ashikhmin

1

对于那些寻找如何确认在WinUI3中关闭Window的人:

Window.Closed事件参数有一个Handled属性,可以将其设置为true以取消关闭。

我非常困惑,与WPF相比,Closed仍然可以被取消。


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