In a Windows 10 Universal app, I want to display a MessageDialog when the back button is pressed.
The code of my page is the following :
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = AppViewBackButtonVisibility.Visible;
SystemNavigationManager.GetForCurrentView().BackRequested += GamePage_BackRequested;
}
private async void GamePage_BackRequested(object sender, BackRequestedEventArgs e)
{
var dialog = new Windows.UI.Popups.MessageDialog("Are you sure ?");
dialog.Commands.Add(new Windows.UI.Popups.UICommand("Yes"));
dialog.Commands.Add(new Windows.UI.Popups.UICommand("No"));
var result = await dialog.ShowAsync();
}
When I lauch the App in "local machine", the dialog is well displayed. But when I turn Windows to "tablet mode", or when i try it on my Windows Phone, the ShowAsync method crashes the App (with no error).
Why is the app crashing ?
The problem seems to be that the "dialog.ShowAsync()" method should be called from the UI thread.
This is how I solved it :
private void GamePage_BackRequested(object sender, BackRequestedEventArgs e)
{
e.Handled = true;
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame.CanGoBack)
{
var d = dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => ShowConfirmationDialog(rootFrame));
}
}
public async void ShowConfirmationDialog(Frame rootFrame)
{
var dialog = new Windows.UI.Popups.MessageDialog("Are you sure ?");
dialog.Commands.Add(new Windows.UI.Popups.UICommand("Yes") { Id = 0 });
dialog.Commands.Add(new Windows.UI.Popups.UICommand("No") { Id = 1 });
var result = await dialog.ShowAsync();
if (result != null && result.Label == "Yes")
{
rootFrame.GoBack();
}
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
dispatcher = Windows.UI.Core.CoreWindow.GetForCurrentThread().Dispatcher;
SystemNavigationManager.GetForCurrentView().BackRequested += GamePage_BackRequested;
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
SystemNavigationManager.GetForCurrentView().BackRequested -= GamePage_BackRequested;
}
You should handle the backrequest ; e.handled = true;
private async void GamePage_BackRequested(object sender, BackRequestedEventArgs e)
{
e.handled = true;
var dialog = new Windows.UI.Popups.MessageDialog("Are you sure ?");
dialog.Commands.Add(new Windows.UI.Popups.UICommand("Yes"));
dialog.Commands.Add(new Windows.UI.Popups.UICommand("No"));
var result = await dialog.ShowAsync();
}
You should add onnavigatedfrom method to unregister the event, otherwise it will trigger twice !
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
if (gb.DetectPlatform() == Platform.WindowsPhone)
HardwareButtons.BackPressed -= HardwareButtons_BackPressed;
elde
SystemNavigationManager.GetForCurrentView().BackRequested -= GamePage_BackRequested;
};
}
There is no way to accomplish what you want -- the back key handler requires an immediate answer (handled or not) but the dialog is inherently async.
You can of course choose to mark the event as Handled before you show the dialog, but then if the user says "Yes" there's no way you can then navigate away. You can of course terminate the app, but that's a bad idea (see final paragraph)
That said, you don't typically need this dialog because in Windows 10, backing out of an app doesn't terminate it, it just switches to the previous app (or the Start menu). The user can trivially return to it via the task switcher (or launching it again).
My UWP application was crashing when I called MessageDialog.ShowAsync in the Application.UnhandledException event handler and this was the top result when I searched for an answer.
I resolved the issue by setting UnhandledExceptionEventArgs.Handled = true before calling MessageDialog.ShowAsync.
This is well documented in another SO question, but I didn't find that answer until after I figured out the solution because I didn't realize calling the method from Application.UnhandledException was significant.
Related
When doubleclicking a button that executes the code
await Navigation.PopModalAsync(true);
the program enters break mode i.e. crashes. How should it be handled so it wont crash when spamclicking?
EDIT
I changed the parameter to false and it works as expected. Is there any workaround to keep the animation set on true?
SOLVED
simple solution:
Boolean _istapped = false;
private async void Button_Clicked(object sender, EventArgs e)
{
if (_istapped)
return;
_istapped = true;
await Navigation.PopModalAsync(true);
_istapped = false;
}
The app crash because when you double click the button, Navigation.PopModalAsync will execute twice and it can't find the page at the second time.
Here is another simple way to solve this problem:
private async void Button_Clicked(object sender, EventArgs e)
{
Button btn = sender as Button;
btn.IsEnabled = false;
await Navigation.PopModalAsync(true);
//btn.IsEnabled = true;
}
In my Xaml Page I've got a Frame.
I'm trying to have a backButton event to just navigate inside frame .
so I tried to use this piece of code
public MainPage(){
this.InitializeComponent();
if(Windows.Foundation.Metadata.ApiInformation.IsTypePresent("Windows.Phone.UI.Input.HardwareButtons")) {
Windows.Phone.UI.Input.HardwareButtons.BackPressed += HardwareButtons_BackPressed;
}
}
private void HardwareButtons_BackPressed(object sender,BackPressedEventArgs e) {
if(insideFrame.CanGoBack())insideFrame.GoBack();
else Application.Current.Exit();
}
but In phone after doing HardwareButtons_BackPressed event it close the application.
It seems to running some default back button behavior on MainPage...
How can I fix it? And In Windows10 does they add new events to handle back navigation?
[Update]
Now I found out it's better to Use SystemNavigationManager in Windows 10 instead of Input.HardwareButtons.BackPressed.
SystemNavigationManager currentView = SystemNavigationManager.GetForCurrentView();
Windows 10 (UWP) include SystemNavigationManager in Windows.UI.Core namespace for Navigation purpose only.
Because SystemNavigationManager is part of Windows Universal Platform, So, it's supported by all device family running on Windows 10 including Mobile and PC.
For Single Page
If you just want to handle navigation for single page. Follow the following steps
Step 1. Use namespace Windows.UI.Core
using Windows.UI.Core;
Step 2. Register back request event for current view. Best place for this is main constructor of class after InitializeComponent().
public MainPage()
{
this.InitializeComponent();
//register back request event for current view
SystemNavigationManager.GetForCurrentView().BackRequested += MainPage_BackRequested;
}
Step 3. Handle BackRequested event
private void Food_BackRequested(object sender, BackRequestedEventArgs e)
{
if (Frame.CanGoBack)
{
Frame.GoBack();
e.Handled = true;
}
}
For Complete Application at one place for single rootFrame
Best place for handling all backbutton for all Views is App.xaml.cs
Step 1. Use namespace Windows.UI.Core
using Windows.UI.Core;
Step 2. Register back request event for current view. Best place for this is OnLaunched just before Window.Current.Activate
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
...
SystemNavigationManager.GetForCurrentView().BackRequested += OnBackRequested;
Window.Current.Activate();
}
Step 3. Handle BackRequested event
private void OnBackRequested(object sender, BackRequestedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame.CanGoBack)
{
rootFrame.GoBack();
e.Handled = true;
}
}
References- Handle back button pressed in UWP
Hope this is helpful to someone!
You need to tell the system that you handled the backbutton press by setting the Handled property of the BackPressedEventArgs to true.
private void OnHardwareButtonsBackPressed(object sender, BackPressedEventArgs e)
{
// This is the missing line!
e.Handled = true;
// Close the App if you are on the startpage
if (mMainFrame.CurrentSourcePageType == typeof(Startpage))
App.Current.Exit();
// Navigate back
if (mMainFrame.CanGoBack)
{
mMainFrame.GoBack();
}
}
follow these steps:
Add two Global Variables in your page as below.
private NavigationHelper navigationHelper;
private RelayCommand _GoBackCommand;
Then add below code in constructor of specific page.
// below code is to override the back navigation
// hardware back button press event from navigationHelper
_GoBackCommand = new RelayCommand
(
() => this.CheckGoBack(),
() => this.CanCheckGoBack()
);
navigationHelper.GoBackCommand = _GoBackCommand;
// ---------
Then add both those methods we've just declared in constructor.
private bool CanCheckGoBack()
{
// this should be always true to make sure the app handles back buton manually.
return true;
}
private void CheckGoBack()
{
// this will be execute when back button will be pressed
}
ps. - for this you might need to use BasicPage instead of BlankPage while adding new page.
hope this will help..!
Try this.It will work for frame back navigation.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
HardwareButtons.BackPressed += HardwareButtons_BackPressed;
}
void HardwareButtons_BackPressed(object sender, BackPressedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
if (Frame.CanGoBack)
{
e.Handled = true;
Frame.GoBack();
}
}
}
I think this is because you add HardwareButtons_BackPressed in your page instead on in app.xaml.cs.
In app.xaml.cs :
public App()
{
this.InitializeComponent();
this.Suspending += this.OnSuspending;
HardwareButtons.BackPressed += HardwareButtons_BackPressed;
}
void HardwareButtons_BackPressed(object sender, BackPressedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame != null && rootFrame.CanGoBack)
{
e.Handled = true;
rootFrame.GoBack();
}
}
Now, back button of your phone will work on any pages.
And then, if you want to add a particular button doing back in any page :
In the particular page (or each pages if you want) :
public void btn_return_Tapped(object sender, TappedRoutedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame != null && rootFrame.CanGoBack)
{
e.Handled = true;
rootFrame.GoBack();
}
}
Source :
http://windowsapptutorials.com/tips/general-tips/handling-the-back-button-in-a-windows-phone-8-1-app/
I want to override the backbutton on mainpage. What works on other pages does not work on main. Here's my code:
protected override void OnNavigatingFrom(System.Windows.Navigation.NavigatingCancelEventArgs e)
{
base.OnNavigatingFrom(e);
if (MessageBox.Show("Wszystkie zmiany zostanÄ… odrzucone", "Odrzucenie Zmian", MessageBoxButton.OKCancel) != MessageBoxResult.OK)
{
e.Cancel = true;
}
}
The problem is that it shows the messagebox to confirm exit, however it is also exiting the application, so confirming or cancelling makes no sense anyway.
You must override OnBackKeyPress instead of OnNavigatingFrom
protected override void OnBackKeyPress(CancelEventArgs e)
{
if (MessageBox.Show("Wszystkie zmiany zostanÄ… odrzucone", "Odrzucenie Zmian", MessageBoxButton.OKCancel) != MessageBoxResult.OK)
{
e.Cancel = true;
}
}
How would I handle the back button for windows mobile 10 and the back button for windows 10 tablet mode? I've been looking everywhere but can't find any examples for it.
This topic is one of the examples used in the Guide to Universal Windows Platform apps . I strongly suggest reading that when getting started with Universal apps.
For the button on the page header use Windows.UI.Core.SystemNavigationManager and set the AppViewBackButtonVisibility property to show or hide the button and handle the BackRequested event to perform the navigation.
Windows.UI.Core.SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = AppViewBackButtonVisibility.Visible;
Windows.UI.Core.SystemNavigationManager.GetForCurrentView().BackRequested += (s,a) =>
{
Debug.WriteLine("BackRequested");
if (Frame.CanGoBack)
{
Frame.GoBack();
a.Handled = true;
}
}
You wire up the hardware back button the same as you do in Windows Phone 8.1, but you should check for the PhoneContract (or the individual class and method) to make sure it is there:
if (ApiInformation.IsApiContractPresent ("Windows.Phone.PhoneContract", 1, 0)) {
Windows.Phone.UI.Input.HardwareButtons.BackPressed += (s, a) =>
{
Debug.WriteLine("BackPressed");
if (Frame.CanGoBack)
{
Frame.GoBack();
a.Handled = true;
}
};
}
Add the following code to your App.xaml.cs and it will handle the navigation on desktop, tablet and mobile (I tested it on the mobile emulator)
for better highlighted differences and explanation (Handling The Back Button In Windows 10 UWP Apps by JEFF PROSISE)
sealed partial class App : Application
{
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
}
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == null)
{
// Create a Frame to act as the navigation context and navigate to the first page
rootFrame = new Frame();
rootFrame.NavigationFailed += OnNavigationFailed;
rootFrame.Navigated += OnNavigated;
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
// TODO: Load state from previously suspended application
}
// Place the frame in the current Window
Window.Current.Content = rootFrame;
// Register a handler for BackRequested events and set the
// visibility of the Back button
SystemNavigationManager.GetForCurrentView().BackRequested += OnBackRequested;
SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility =
rootFrame.CanGoBack ?
AppViewBackButtonVisibility.Visible :
AppViewBackButtonVisibility.Collapsed;
}
if (rootFrame.Content == null)
{
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
rootFrame.Navigate(typeof(MainPage), e.Arguments);
}
// Ensure the current window is active
Window.Current.Activate();
}
void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
{
throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
}
private void OnNavigated(object sender, NavigationEventArgs e)
{
// Each time a navigation event occurs, update the Back button's visibility
SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility =
((Frame)sender).CanGoBack ?
AppViewBackButtonVisibility.Visible :
AppViewBackButtonVisibility.Collapsed;
}
private void OnSuspending(object sender, SuspendingEventArgs e)
{
var deferral = e.SuspendingOperation.GetDeferral();
// TODO: Save application state and stop any background activity
deferral.Complete();
}
private void OnBackRequested(object sender, BackRequestedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame.CanGoBack)
{
e.Handled = true;
rootFrame.GoBack();
}
}
}
I have two pages in my app.One is blankPage and other is basic page. On basic page I want to provide a message if a user press back button like
"Are you sure you want to quit" .If Yes then go back else remain there , this working fine by using this code
HardwareButtons.BackPressed += HardwareButtons_BackPressed;
private async void HardwareButtons_BackPressed(object sender, BackPressedEventArgs e)
{
e.Handled = true;
MessageDialog dlg = new MessageDialog("Are you sure you want to quit you will loose all your work ?", "Warning");
dlg.Commands.Add(new UICommand("Yes", new UICommandInvokedHandler(CommandHandler1)));
dlg.Commands.Add(new UICommand("No", new UICommandInvokedHandler(CommandHandler1)));
await dlg.ShowAsync();
}
private void CommandHandler1(IUICommand command)
{
var label = command.Label;
switch (label)
{
case "Yes":
{
this.Frame.Navigate(typeof(MainPage));
break;
}
case "No":
{
break;
}
}
}
But when I am pressing back button on my BlankPage this message also appears there and also appearing in all other basic page if I add more . What mistake am I doing??
You are registering hardware back button in page constructor or page load event and once this event is registered you are not unregistering this event. BackPress is app level. for correctly using this event on your desired page register Back Press event in your OnNavigatedTo override method and unregister this event in OnNavigatedFrom ovrride metho. here is how.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
Windows.Phone.UI.Input.HardwareButtons.BackPressed += HardwareButtons_BackPressed;
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
Windows.Phone.UI.Input.HardwareButtons.BackPressed -= HardwareButtons_BackPressed;
}