Windows Phone back button to terminate the app - windows-phone-7

I have a main page with some options. One of them is to navigate to page 1 where there are two arrows. One that navigates to page2, page3, and the other arrow page3, page2, page1 like a loop. There is also an arrow that navigates to main page.
I want to ask if there is a way when the user presses the back button to terminate the app from whatever page the user is currently at and not to navigate through all pages.
edit
if i want when i press the back to always navigate to the mainpage what i have to do ?

clear the back stack inside the onbackkeypress function where you want to exit the app. And it will exit the app normally.
[Updated]
1) after clearing back stack. Use NavigationService.Navigate(new Uri("MainPage.xaml",UriKind.Relative)); to traverse to mainpage and do e.Cancel = true in the next statement.
2) Or clear the back stack upto the mainpage. and automatically the back press will take you to the mainpage. inside the mainpage clear the back stack fully inside the OnNavigatedTo function so that the first item is always your mainpage and user can exit easily.
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
while (NavigationService.CanGoBack)
NavigationService.RemoveBackEntry();
e.Cancel = true;
return;
}

protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
while (NavigationService.CanGoBack)
NavigationService.RemoveBackEntry();
}

Throw an exception in OnBackKeyPress which terminates the app.
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
throw an exception();
}

You can also do like this,
check
e.NavigationMode == System.Windows.Navigation.NavigationMode.Back
in OnNavigatedTo event (you need to override this every page) and call
NavigationService.GoBack();
there is no direct way of exiting an app.. see here

hope this will work. If its XNA
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();

Related

Detect Back Arrow Press Of The NavigationPage in Xamarin Forms

Is there any way to detect the press of the back button of the Navigation Page in Xamarin forms?
You can override your navigation page "OnBackButtonPressed" method:
protected override bool OnBackButtonPressed()
{
Device.BeginInvokeOnMainThread(async () =>
{
if (await DisplayAlert("Exit?", "Are you sure you want to exit from this page?", "Yes", "No"))
{
base.OnBackButtonPressed();
await App.Navigation.PopAsync();
}
});
return true;
}
If you are using the shell, you can override the Shell's OnNavigating event:
void OnNavigating(object sender, ShellNavigatingEventArgs e)
{
// Cancel back navigation if data is unsaved
if (e.Source == ShellNavigationSource.Pop && !dataSaved)
{
e.Cancel();
}
}
Update:
OnBackButtonPressed event will get fired ONLY on Android when user press the Hardware back button.
Seems like you are more interested to implement when any page get disappeared you want to do something!
In that case:
You have the page's two methods -
protected override void OnAppearing()
{
base.OnAppearing();
Console.WriteLine("Hey, Im coming to your screen");
}
protected override void OnDisappearing()
{
base.OnDisappearing();
Console.WriteLine("Hey, Im going from your screen");
}
You can override those 2 methods on any page to track when they appear and disappear.
Recent updates to Xamarin forms mean you can now do this in an application made with Shell Navigation for navigation back arrow on both platforms.
Use the Shell.SetBackButtonBehavior method, for example running this code in the constructor of your page object will allow the back navigation to take place only when the bound viewmodel is not busy:
Shell.SetBackButtonBehavior(this, new BackButtonBehavior
{
Command = new Command(async() =>
{
if (ViewModel.IsNotBusy)
{
await Shell.Current.Navigation.PopAsync();
}
})
});
In the body of the Command you can do whatever you need to do when you are intercepting the click of the back button.
Note that this will affect only the navigation back button, not the Android hardware back button - that will need handling separately as per the answers above. You could write a shared method called from both the back button pressed override and the command on shell back button behaviour places to share the logic.
You must override native navigationbar button behavior with custom renderer. OnBackButtonPressed triggers only physical device button. You can read good article how to achive this here

How to handle OnBackKeyPress correctly?

To make it simple, I create a new app, which contains MainPage, and Page2.
MainPage has a button, which navigates to Page2. Also override MainPage.OnBackKeyPress:
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
if (MessageBox.Show("Quit?", "Confirm", MessageBoxButton.OKCancel) == MessageBoxResult.Cancel)
e.Cancel = true;
else
base.OnBackKeyPress(e);
}
Page2 is empty, except override OnNavigateFrom, to simulate a long time operation when back from Page2 to MainPage:
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
System.Threading.Thread.Sleep(1000);
base.OnNavigatedFrom(e);
}
Everything is ok, but when I am at Page2, and press Back key 3-4 times very quickly, then I see the message box popup twice.
I expect the message box not shown, or at least show and hide. Is there anything wrong in my code? Thanks.
It depends on what you mean by very quickly...
The code looks OK (apart from the Thread.Sleep which is presumably to simulate a long operation on the UI thread).
I expect this is because while the UI thread is busy (or "sleeping") the back key presses are still registering and being sent to the app, and when the UI thread is available again it will process them one after the other.
This is a good example of why you should avoid blocking the UI thread.

Do code after OnNavigatedTo

I Have Code get IdUsers From Other Page
String IdUsers;
public Main_Wallets_Page()
{
InitializeComponent();
MessageBox.Show(IdUsers);
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
String Id;
if (NavigationContext.QueryString.TryGetValue("IdUsers", out Id))
IdUsers = Id;
}
The MessageBox Alway be Null. I Want to MessageBox Show the "IdUsers" after OnNavigationTo (Do not put the MessageBox IN "OnNavigationTo").
How can i do it ?
You shouldn't use MessageBoxes in OnNavigatedTo because if the user does not press a button your app will crash since the framework thinks that navigation has failed. MessageBoxes in the constructor are equally as bad.
I can think of two options (I use #1 for these sorts of things):
Show the MessageBox in the Loaded event. But be careful it can be
fired more than once. In the constructor you might add the handler for the Loaded event and then in the handler you'd detach from the handler so that it is called only once.
Use Dispatcher.BeginInvoke around the MessageBox.Show call so that it does not block navigation. That might still block the Dispatcher thread. If you really wanted to go this route you could use ThreadPool.QueueUserWorkItem or a TPL Task.
I also have used OnLayoutUpdated in place of the Loaded event but I can't remember exactly why :) It seems like it might have been that the page hasn't yet displayed in Loaded and it has in the other event.
If this value was initialized, you can store it in application isolated storage. Then, when constructor is called, you can read it from there. In this case value of user ID will be initialized and MessageBox won't show you NULL.
DO NOT place MessageBox into OnNavigatedTo event.
Try to create an empty project with MainPage and Page2. Place button on MainPage to navigate to Page2. In Page2 place MessageBox in OnNavigatedTo event. Then everythig will work fine if you Start Debugging from VS. BUT if you deploy and run it you will see that when you navigate to Page2 you see MessageBox. Then don't do anything, just wait for about 15 sec. MessageBox will react as Canceled and APPLICATION WILL BE CRASHED! without any navigation to Page2 or MainPage. The same thing happens if you use Dispatcher.BeginInvoke around the MessageBox.Show.
I assume that OnNavigatedTo event has a timeout which works only when app is deployed. So you should run your MessageBox when Navigation is competed.
Everything works if you do
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) {
base.OnNavigatedTo(e);
var lcTimer = new DispatcherTimer { Interval = new TimeSpan(0, 0, 0, 0, 200) };
lcTimer.Tick += (s2, e2) => {
(s2 as DispatcherTimer).Stop();
if (MessageBoxResult.OK == MessageBox.Show("Test, don't push", "", MessageBoxButton.OKCancel))
MessageBox.Show("OK");
else
MessageBox.Show("Cancel");
};
lcTimer.Start();
}
Note: If you have some code in OnNavigatedTo run above code at the end of OnNavigatedTo.
I liked what Austin Thompson(upvote) has adviced with ThreadPool.QueueUserWorkItem. But note that with this approach you need to place MessageBox inside the Dispatcher.BeginInvoke otherwise you will receive cross-thread exception. So the code is the following
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) {
base.OnNavigatedTo(e);
ThreadPool.QueueUserWorkItem((stateInfo) => {
Dispatcher.BeginInvoke(() => {
if (MessageBoxResult.OK == MessageBox.Show("Test don't push", "", MessageBoxButton.OKCancel))
MessageBox.Show("OK");
else
MessageBox.Show("Cancel");
});
});
}

Navigation loop and clearing back-stack

Right now, what I have is, when the user clicks on the page, the page will automatically send the user to a webtask which opens up a pdf file.
What's happening right now is when the user presses the back button, it goes back to the Original page for a split second, before being redirected back to the pdf as I have assigned it to (due to the onnavigateto function)
How would I make it so that, when the user clicks the back button in the pdf document, the app will take the user back to the main page?
Also, on the main page, how do I ensure that the backstack is cleared? (As the Application HAS to exit on the MainPage, so can't go back to the pdf.)
My Code so far, I have tried...
{
public partial class Page2 : PhoneApplicationPage
{
public Page2()
{
InitializeComponent();
}
//as soon as this page is opened, navigate/redirect it to the URL below
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
WebBrowserTask task = new WebBrowserTask() { URL ="http://test.com/test.pdf"};
task.Show();
}
//when the user clicks the hardware back button, instead of taking them to the daily notices, which will send them back to brower
// send the user to the main page
protected override void OnBackKeyPress
(System.ComponentModel.CancelEventArgs e)
{
base.OnBackKeyPress(e);
new Uri("/MainPage.xaml", UriKind.Relative);
}
First of all, why you need the second page that only opens a WebBrowserTask? You can do this from main page.
If you still want to open from second page, you can move WebBrowserTask to constructor and surround it with Dispatcher. This approach is guaranteed that WebBrowserTask will be called only once after navigation to this page (maybe will be some problems with tombstoning). Or, you can save state to PhoneApplicationPage.State to handle where user was and what you should open next.
For clearing back stack you can use next code:
while (NavigationService.BackStack.Any())
{
NavigationService.RemoveBackEntry();
}
You will have to detect this on the application level, rather than the page level. When you 'redirect' the user to the PDF, your application becomes suspended. When they then navigate back, it is resumed.
The Visual Studio template provides a method that it invoked when the application resumes:
// Code to execute when the application is activated (brought to foreground)
// This code will not execute when the application is first launched
private void Application_Activated(object sender, ActivatedEventArgs e)
{
}
Within the above method, you could set a flag, that you then check when your page is navigated to,, that indicates a resume has occurred.

How to load MainPage when goBack(); form SecondPage?

I use NavigationService.Navigate("..."). But I want to load MainPage again when I click the Back button by event goBack();
In your goBack method you can use the NavigationService.GoBack() call to move from SecondPage back to the MainPage. You can view all the Navigation methods available to you on MSDN.
You can override the method OnBackKeyPress, and inside the method write code shown below, it ll navigate to MainPage.xaml
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
NavigationService.Navigate(new Uri("/MainPage.xaml", UriKind.Relative));
}
If you are using binding do this:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
App.ViewModel.LoadData();
}
And in MainViewModel.cs
public void LoadData()
{
Items.Clear();
this.Items.Add(new ItemViewModel() { LineOne = "runtime one", LineTwo = "Data info 2" });
this.IsDataLoaded = true; }
Like Nigel said, you can use NavigationService.GoBack() however this will only work if you went from the MainPage to the second page.
The only other way to do this is how you have mentioned using NavigationService.Navigate(uri).
Override the navigated to event
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
if (PhoneApplicationService.Current.State["msg"].ToString() == "from page2")
{
// do something when its comming from page2
}
base.OnNavigatedTo(e);
}
Now that will trigger every time its navigated to but you could send some parameters so you know what to depending on what page it came from.
PhoneApplicationService.Current.State["msg"] = "from page2";
NavigationService.Navigate(new Uri("/MainPage.xaml?msg=", UriKind.Relative));
There are two ways to get back to your MainPage.
(First Method) Override the OnBackKeyPress() and write the following snippet inside it.
NavigationService.GoBack();
Note :
This will move to the MainPage only if the MainPage is the previous page in your Navigation history.
(Second Method) Override the OnBackKeyPress() and write the following snippet inside it.
NavigationService.Navigation(new Url("/MainPage.xaml",UriKind.Relative));
Note :
This will create a New MainPage and navigates to it. So if you navigated from MainPage to SecondPage and if you navigate again to MainPage using the above snippet, you will be having two MainPage in your Navigation history.
So, use any one of the snippet according to your scenario.
if WP7 or WP8 : NavigationService.GoBack()
if WP8.1 : Frame.GoBack();
and you can Override the navigated to event
protected override void
OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) {
// do nothing }
I don't recommend overriding the OnBackKeyPress method and calling NavigationService.Navigate method within it as it may mess up your page back stack.
I assume your app has more than 2 pages. Otherwise you should just call NavigateService.GoBack() as others have recommended.
Example
Start on MainPage (backstack: empty)
Navigate to SecondPage (backstack: MainPage)
Navigate to ThirdPage (backstack: SecondPage, MainPage)
Click the back button (overridden) and you are taken to MainPage (backstack: ThirdPage, SecondPage, MainPage)
Click the back button and you are taken to the ThirdPage (backstack: SecondPage, MainPage). This is not the expected behaviour as the application should have exited.
Now you're stuck in a back button loop.
Solution
Override OnNavigatingFrom and remove any of the backstack entries you don't want the user to go to. You can either allow the user to press the back button to get back to the MainPage from the ThirdPage or you can call NavigationService.GoBack().
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
base.OnNavigatingFrom(e);
// Remove all backstack entries except for the first one
while(NavigationService.BackStack.Count() > 1)
{
NavigationService.RemoveBackEntry();
}
}

Resources