Is there a way to handle OnBackKeyPress in such way that it returns to the actual page in the back-stack instead of going back to another instance of the same page? This is the code I have:
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
e.Cancel = true;
base.OnBackKeyPress(e);
this.NavigationService.Navigate(new Uri("/MainPage.xaml", UriKind.Relative));
}
But it doesn't do what I want. is there a way to do this without using the NavigationService and getting the actual page in the back-stack instead?
Thanks.
The short answer is no you can't do that. Other than using the NavigationService to move backwards page by page there is no way to manipulate the back stack. Rightly or wrongly this is by design. And it kind of makes sense as they need to sure that the operation of the back button is consistent.
What you are trying to do is actually change the behavior of the back button. Which is not what the OnBackKeyPress is intended for. The WP7 Design Guide says the following about the back button:
The back button can close an on-screen
keyboard, menus, dialogs, navigate to
a previous page, exit a search
operation or even switch between
applications. However the principal
usage is to move from a current screen
to a previous screen.
If your scenario is not covered in the by the above I would suggest maybe you are trying to do something which is fundamentally in consistent with Microsoft's intentions for the back button.
If your reason for wanting this behavior is to maintain state on your previous page when navigating back, you can achieve this using dependency injection and the MVVM pattern. You can register a singleton/instance of your viewmodel in your dependency container. That way when your view gets navigated to via the back button, you can inject that single instance of the viewmodel into the view and have the previous state if you rely on the binding techniques of MVVM.
I know that there's a phone version of Ninject floating around for a dependency container so you don't need to roll your own injection container (just search for Ninject wp7).
I was able to fix it. This was the problem:
MainPage -> SettingsPage -> SetLocationPage
Once location was set, we sent the user back to SettingsPage with NavigationService.Navigate, then when the user pressed the back button in the SettingsPage it would go back again to the SetLocation, when it made more sense to send it to the MainPage.
This is how it was:
SetLocation -> SettingsPage -> (Back button) -> SetLocationPage
Now, I'm using NavigationService.GoBack instead of NavigationService.Navigate in the SetLocationPage:
SetLocationPage (once location is set use GoBack()) -> SettingsPage (use GoBack here too) -> MainPage.
Navigation now makes sense, and I solved it using NavigationService.GoBack().
Thanks for everyone's input.
I'm curious what you trying to do here and why you need to navigate to implement back.
Ordinarily you dont implement the override and the user presses back, and the NavigationService automagically takes the user to the previous bage in the back stack.
If this is not the case can you elaborate on why. There is some information that may help, but I suspect it would be a band-aid on top of an existing problem at the moment.
Related
I know in Xamarin we can use Tabbed page, Carousel page... but I wonder that if I open every new page like this:
Application.Current.MainPage = new MyPage();
Is this a bad approach? Is this effect performance or any other things?
Basically when you use PushAsync, it adds the new page on top of the navigation stack. The navigation stack is a LIFO you can manage using PushAsync, PopAsync or the back button. So when you use PopAsync, it removes the last page from the stack (as it does using the back button).
Using Application.Current.MainPage = new MyPage(); for opening every page, you are just overriding the very first element of the stack and therefore you are not able to use back navigation at all since you would always keep one single page into the navigation stack.
Moreover, with this approach, clicking on the back button will exit the app.
You can do this as long as it works for you. However it may cause some problems, especially that you can't use the system back function in any way. Also you may lose some animations that should be part of the standard UI and that are considered as a good practice.
I am doing xamarin development and I am not doing forms.
I want to go back by 3 viewcontrollers/activities but goback method is for going back by one viewcontroller or activity
If I use navigateto i believe one more time the viewcontrolller/activity gets added.i.e two instances.
So how to solve this problem ?
Update:
Here is the inavigation interface there is no way to access thr navigational stack as well
If you are going back, then use INavigationService.GoBack();. You can call that 3 times in a row to go back 3 pages.
private void GoBackThree()
{
_navigationService.GoBack();
_navigationService.GoBack();
_navigationService.GoBack();
}
I haven't used MVVM Light before but I have quite a bit of experience of Xamarin Forms. I used to use MVVM Cross for navigation but eventually found that the built in Xamarin Forms Navigation was much better, I ran into similar scenarios as to what you have here.
Under the hood it looks like MVVM Light is just wrapping the Xamarin Forms Navigation anyway - http://mvvmlight.codeplex.com/SourceControl/latest#Samples/Flowers/Flowers.Forms/Flowers.Forms/Helpers/NavigationService.cs
I don't think you need give up on MVVM Light navigation but you do need to get under the hood to achieve the navigation without seeing three transitions. I haven't tried this with MVVM Light but it works great with normal Forms navigation.
Step 1
Get access to the underlying Xamarin Forms navigation:
var navigation = Application.Current.MainPage.Navigation;
Step 2
Remove the two pages you want to skip when navigating back. It's important that you remove them before navigating backwards otherwise you'll get a double transition (note the -2 is because you want to remove the second to last page).
var firstPageToRemove = navigation.NavigationStack[navigation.NavigationStack.Count - 2];
navigation.RemovePage(firstPageToRemove);
var secondPageToRemove = navigation.NavigationStack[navigation.NavigationStack.Count - 2];
navigation.RemovePage(secondPageToRemove);
Step 3
Navigate backwards
_navigationService.GoBack();
I hope that works for you.
Alternative Consideration
I have a similar application in my app which I've solved a little more elegantly. If you know you never need to be able to navigate back to those previous pages. When you push the new pages on, you can actually remove the previous one if you no longer need it. Please note you have to remove the page after you push on the new one otherwise you get two transitions. I use this extension method on-top of the standard Forms Navigation which I showed you how to access in Step 1 to achieve it.
public static async Task ReplaceCurrentAsync(this INavigation navigation, Page page, bool animated = false)
{
var curentPage = navigation.NavigationStack.Last();
await navigation.PushAsync(page, animated);
navigation.RemovePage(curentPage);
}
I have another wxWidgets question regarding events and focus.
I have already looked at the tutorials and this old question here but I am still running into problems C++ Event (Focus) Handling
Basically I have a dialog with two wxTextCtrl elements and a Button.
What I would like to achieve is, that when I click on button it needs to tell me which of the two elements previously had the focus.
In the constructor of my Dialog I created all the elements and then connected them to the eventhandler like this: Ttop->Connect(TOP,wxEVT_KILL_FOCUS,(wxObjectEventFunction)&UI_ADDENTRY::hasfocus);
Tbottom->Connect(BOTTOM,wxEVT_KILL_FOCUS,(wxObjectEventFunction)&UI_ADDENTRY::hasfocus);
then there is the eventhandler that safes the id into focus
void UI_ADDENTRY::hasfocus(wxFocusEvent& event){
focus= event.GetId();
event.Skip();}
however when i try to access focus in the Button function it always tells me: 0 instead of TOP or BOTTOM / the ids that I gave the textcontrols
void UI_ADDENTRY::OnRecord(wxCommandEvent &event){
wxString tmp;
tmp << this->focus;
wxMessageBox(tmp);}
What am I doing wrong? is there another way of finding out which of the two textbox has been in focus last?
Thank you
The most fool proof way is to catch EVT_SET_FOCUS in your text controls and remember the last one that received it. This is not more difficult than what you are doing but should work without problems.
FWIW EVT_KILL_FOCUS can't, unfortunately, be consistently implemented on all platforms, in particular GTK+ doesn't give any information about the window focus is being lost to.
In think u mean event.GetWindow().GetId(). Though I'm not sure how ur casting from int to string.
I have a page that I am navigating to that does some setup stuff via the 'OnNavigatedTo' event.
Thso page contains a TimePicker control and I have discovered that when I finish in the Timepicker control and focus returns back to my page it is again going through the 'OnNavigatedTo' event.
As a result is doing setup stuff again that is mucking things up, and if even has the same NavigationContext.QueryString as when I originally navigated to that page.
I assume I cannot avoid this event being called again - but is there any way to know that I have come here as a result of exiting the Timepicker control?
thanks
What about defining a bool in the class (instance-level, not static) that you set check in OnNavigatedTo -- if false, then do your work and set to true. Now, I'm not 100% sure that this works if you go back one level further and then tap on whatever brought up this page, so check that. Also, check to ensure everything works with tombstoning -- that's where you're more likely to have problems.
--randy
I'm wondering how I can give the focus back to the window that it before my window got it. I've looked around and so far only seen functions to get, not release, focus.
I wonder if you just need the focus released, or do you need to focus on another entity instead, after releasing the focus from said entity?
If you need to know previous widget in your form tab order, take a look at QWidget::nextInFocusChain and QWidget::previousInFocusChain. You should be able to get next\previous widget in your widget's focus chain. Once you know it, you can pass focus to it.
If you're looking to get next\previous window in Z-order take a look at winapi GetNextWindow function (GW_HWNDPREV in wCmd parameter will return a handle to the window above the given window). Once you know the previous window you can bring it back to from using BringWindowToTop
hope this helps, regards