Potvrzení ukončení aplikace v UWP

WinUI

5 years ago

Jedním z častých požadavků vývojářů aplikací je možnost zobrazit potvrzovací dialog při zavírání aplikace. Přestože tento scénář je méně a méně relevantní ve světě mobilních aplikací a dat hostovaných v cloudu, může být přesto v některých případech užitečný. V tomto článku si ukážeme jak jej implementovat v UWP.

API

Ačkoliv Microsoft Edge podporoval tuto funkcionalitu již od počátku, API bylo zveřejněno až ve Windows 10 Creators Update (15063) a vyžaduje deklaraci restricted capability. Klíčem k API je třídaSystemNavigationManagerPreview v jmenném prostoruWindows.UI.Core.Preview. Podobně jako jiná API pracující s UI je přímo vázána na UI vlákno a její instanci lze získat pouze z něj pomocí metody GetForCurrentView(). Poté musíme zpracovat událost CloseRequested, ke které dojde při stisknutí zavíracího tlačítka v title baru aplikace nebo při pokusu o zavření přes task bar. Dobré místo pro navázání této události je vApp.xaml.cs před tím, než je okno aktivováno:

SystemNavigationManagerPreview.GetForCurrentView().CloseRequested += App_CloseRequested;
// Ensure the current window is active
Window.Current.Activate();

Implementace potvrzení

Událost CloseRequested má parametr SystemNavigationCloseRequestedPreviewEventArgs, který obsahuje vlastnost Handled, která může být nastavena na true, když chceme zabránit zavření aplikace. To však skýtá malý háček - většinou chceme nechat uživatele o tomto rozhodnout pomocí nějakého dialogu, ale taková operace je inherentně asynchronní, což však znamená že náš handler události skončí před tím, než budeme schopni vlastnost Handled správně nastavit. Naštěstí zde můžeme použít Deferral, což je obvyklé řešení podobných situací v UWP. Na začátku event handleru si vyžádáme instanci deferralu pomocí metody GetDeferral. Systém tím ví, že musí čekat na volání Completed() předtím než bude vyhodnocovat vlastnost Handled:

private async void App_CloseRequested(object sender, SystemNavigationCloseRequestedPreviewEventArgs e)
{
    var deferral = e.GetDeferral();
    var dialog = new MessageDialog("Are you sure you want to exit?", "Exit");
    var confirmCommand = new UICommand("Yes");
    var cancelCommand = new UICommand("No");
    dialog.Commands.Add(confirmCommand);
    dialog.Commands.Add(cancelCommand);
    if (await dialog.ShowAsync() == cancelCommand)
    {
        //cancel close by handling the event
        e.Handled = true;
    }
    deferral.Complete();
}

Přidání capability

Protože potvrzení uzavření aplikace je restricted capability, je třeba ji explicitně specifikovat v manifestu aplikace. Když je pak aplikace certifikována v Microsoft Store, bude tato funkčnost manuálně testována pro ověření, že ji nezneužíváme, abychom zabránili uživateli aplikaci jednoduše zavřít. Klikneme pravým tlačítkem myši na soubor Package.appxmanifest v Solution Exploreru a vybereme View code. V elementu Pacakage deklarujeme XML jmenný prostor rescap a upravíme atribut IgnorableNamespaces:

<Package ...
  xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
  IgnorableNamespaces="uap mp rescap">

Nyní scrollujme dolů do sekce Capabilities a deklarujeme confirmAppClose:

<rescap:Capability Name="confirmAppClose" />

Nyní můžeme aplikaci spustit a zkusit zavřít. Měl by se zobrazit potvrzovací dialog a v závislosti na tlačítku které vybereme by se měla aplikace buď zavřít nebo zůstat otevřená.

Zdrojový kód

Ukázkový zdrojový kód pro tento článek je dostupný na mém GitHubu.

Shrnutí

Implementovali jsme potvrzení o zavření aplikace v UWP. Kromě nutnosti deklarovat capability v manifestu jde o přímočarý proces a dokonce umožňuje zobrazovat potvrzovací UI asynchronně.