Łukasz Włodarczyk Łukasz Włodarczyk - 3 months ago 91
C# Question

Close App Confirmation using MessageDialog for Windows Phone 8.1 using C#

I've got a problem with the Windows.UI.Popups.MessageDialog class. The thing is:
I want to ask the user if (s) he wants to close the app, when clicking the back button (on the first Page). I've tried two approaches:

First is setting the BackPressed method async:

private async void HardwareButtons_BackPressed(object sender, Windows.Phone.UI.Input.BackPressedEventArgs e)
{
Windows.UI.Popups.MessageDialog logout = new Windows.UI.Popups.MessageDialog("Do You want to close the app?");
logout.Commands.Add(new Windows.UI.Popups.UICommand("Yes", Exit));
logout.Commands.Add(new Windows.UI.Popups.UICommand("No"));
await logout.ShowAsync();
}


Second is using the System.Threading.Tasks.Task.WaitAny(...) method:

private void HardwareButtons_BackPressed(object sender, Windows.Phone.UI.Input.BackPressedEventArgs e)
{
Windows.UI.Popups.MessageDialog logout = new Windows.UI.Popups.MessageDialog("Do You want to close the app?");
logout.Commands.Add(new Windows.UI.Popups.UICommand("Yes", Exit));
logout.Commands.Add(new Windows.UI.Popups.UICommand("No"));
System.Threading.Tasks.Task.WaitAny(logout.ShowAsync().AsTask());
}


What I get is:

First: the MessageDialog shows just for a sec, then app minimizes, switching to it, and pressing the back button, just minimizes app again, but MessageDialog is not shown).

Second: it's a deadlock (after clicking "Yes", MessageDialog closes, but the Exit() method is not called, app freezes).

Answer

First of all:

Microsoft recommends that apps not close themselves programmatically.

See here:

App lifecycle - Windows app development

That page says:

You can't include any UI in your app to enable the user to close your app, or it won't pass the Store certification process.

Although I know that there are apps in the Store that do this anyway.


Anyway, in the HardwareButtons_BackPressed event handler, e.Handled = true; is needed to prevent the app from closing. This also applies for when navigating backwards in your app.

Besides this, Frame.CanGoBack should be checked to see if the app should navigate or close.

Also, you should not need to use a task, but just await MessageDialog.ShowAsync(), although you could create a task that returns a boolean telling whether to proceed or not.


Here is an entire code example to use that handles navigating backwards in the frame stack and displays a message dialog asking whether to close the app or not when the first frame is reached:

App.xaml.cs:

using Windows.Phone.UI.Input;
using Windows.UI.Popups;

public sealed partial class App : Application
{

    public App()
    {
        HardwareButtons.BackPressed += HardwareButtons_BackPressed;
    }

    private async void HardwareButtons_BackPressed(object sender, BackPressedEventArgs e)
    {
        Frame frame = Window.Current.Content as Frame;
        if (frame == null) { return; }
        e.Handled = true;
        if (frame.CanGoBack) { frame.GoBack(); return; }
        else
        {
            string content = "Do you want to close the app?";
            string title = "Close Confirmation";
            MessageDialog confirmDialog = new MessageDialog(content, title);
            confirmDialog.Commands.Add(new UICommand("Yes"));
            confirmDialog.Commands.Add(new UICommand("No"));
            var confirmResult = await confirmDialog.ShowAsync();
            // "No" button pressed: Keep the app open.
            if (confirmResult != null && confirmResult.Label == "No") { return; }
            // "Back" or "Yes" button pressed: Close the app.
            if (confirmResult == null || confirmResult.Label == "Yes") { Current.Exit(); }
        }
    }

}