UWPアプリが閉じられるのをキャンセルする
- アプリを終了する操作をキャンセルできます
- サイドローディングで配布する業務アプリを想定した機能で、ストアでの公開は制限されます
- Windows 10 version 1703(build 15063)から利用可能
アプリが閉じられようとするときのイベントハンドラーが使えるようになりました。そのイベントハンドラーに渡された引数のHandledプロパティをtrueにセットすれば、閉じられるのをキャンセルできます。[×]ボタン/[Alt]+[F4]キー/タスクバーからの終了操作など、ユーザーがアプリを終了しようとする操作をキャンセルできます。
この機能はサイドローディングで配布する業務アプリなどを想定しているようで、Microsoftストアでは制限されます。ストアでは、ファイルの「フルアクセス機能」と同様の扱いになります。
マニフェストの変更
この機能を使うには、「制限付き機能」(restricted capabilities)であるconfirmAppCloseケイパビリティの宣言がマニフェストに必要です(capability=ある目的の達成に必要な能力)。
ソリューションエクスプローラーでPackage.appxmanifestを右クリックし、[コードの表示]を選んで、マニフェストを直接編集します。
まず、先頭のPackage
タグに名前空間「rescap」を追加します(次のコード)。
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" IgnorableNamespaces="uap mp rescap">
次に、Capabilities
要素の中に、次のコードのようにrescap:Capability
要素を追加します。Capabilities
要素が見当たらないときは、</Package>
閉じタグの上にCapabilities
要素を追加してください。
<Capabilities> <Capability Name="internetClient" /> <rescap:Capability Name="confirmAppClose" /> </Capabilities> </Package>
ここでrescap
は"restricted capability"(制限されているケイパビリティ)の意味です。また、rescap:Capability
要素を記述すると警告が出るかもしれませんが、無視してください。なお、rescap:Capability
要素を記述すると、WACK(Windows App Cert. Kit)のテストには通らなくなります。
アプリが閉じられるのをキャンセルするコード
以上のようにマニフェストを修正すると、SystemNavigationManagerPreviewクラス(Windows.UI.Core.Preview名前空間)のCloseRequestedイベントが使えるようになります。アプリが閉じられるのをキャンセルするには、そのイベントハンドラーの中で引数のHandledプロパティにtrueをセットします(次のコード)。
SystemNavigationManagerPreview.GetForCurrentView().CloseRequested += (s, e) => { // 閉じられるのをキャンセルする e.Handled = true; };
上のようにしただけではアプリをまったく終了できなくなってしまいますから、実際には次のコードのように、ダイアログを出してユーザーに決めてもらうようにします。awaitしてから(=いったん制御を返してしまってから)Handledプロパティを変更しても間に合わない(=アプリは閉じてしまう)ことには注意してください。つまり、ダイアログを出す前にHandledプロパティを変更しておく必要があります。ユーザーが終了することを選んだら、あらためてAppクラスのExitメソッドを呼び出してアプリを終了させます。
SystemNavigationManagerPreview.GetForCurrentView().CloseRequested += async (s, e) => { // 閉じられるのをキャンセルする e.Handled = true; // ダイアログを表示する ContentDialog dialog = new ContentDialog { Title = "アプリを終了しますか?", Content = "[×] ボタンが押されましたが、アプリを終了してもよいですか", CloseButtonText = "キャンセル", PrimaryButtonText = "終了", DefaultButton = ContentDialogButton.Primary }; ContentDialogResult result = await dialog.ShowAsync(); if (result == ContentDialogResult.Primary) { // すでにキャンセルしてしまっているので、 // 必要ならばあらためてアプリを終了させる。 App.Current.Exit(); // ↑Exitすると、OnSuspendingなどは実行されないので注意! } };
なお、Exitメソッドでの終了は「異常終了」です。OnSuspendingイベントなどは発生しませんので、アプリ中断時に行う処理はExitメソッドを呼び出す前に終わらせておいてください。また、終了時のウィンドウの位置やサイズも記憶されません(サンプルコードにはウィンドウサイズを復元するコードを入れてあります)。