Xamarin Forms page navigation - xamarin

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.

Related

Accessible AJAX page transitions for SPA

I have been tasked with building a SPA that has some complex page transitions.
My biggest concern is that these transitions rely on elements expanding on the page to then become the full page (i.e. you click a blue button, the blue background expands to fill the whole page and then the content is displayed.)
Now this is where I am struggling to come up with an accessible solution. I thought about making the text within the original 'button' a link with padding (as the URL will update and the link is for no JavaScript fallback) and then replacing the content of the parent div (the blue background) with the new content.
The problem I have is that I am not sure what would be the best practice for accessibility from the perspective of letting a screen reader user know that a new page has loaded in. Using aria-live is a terrible idea, but with NVDA if I just replace the contents of the div it can have some strange behaviour.
Has anyone ever come across this before? For example this dribble nearly shows what I mean, you click an element and then it opens up into a new page with the content within the element.
For a 'normal' AJAX site when navigating I would simply replace the whole <main> with the new content, make the <h1> programatically focused with a tabindex="-1", update the page <title> and that works fine, but with this type of navigation I am wondering if the same approach is applicable.
I am thinking replacing everything within the <main> element except for the selected 'button' background (including the original link being removed once the new page has loaded) and then loading the content in and managing the focus as described would work, but I am not sure if there is an accepted pattern for this type of navigation as it is so unusual.
I am thinking replacing everything within the element except
for the selected 'button' background (including the original link
being removed once the new page has loaded) and then loading the
content in and managing the focus as described would work, but I am
not sure if there is an accepted pattern for this type of navigation
as it is so unusual
I think this is your best best. The whole visual expanding thing is just eye candy, so as long as it is there you should be able to do this behind the scenes. Make sure you test with screen readers.

How to go back more than one view model in mvvm light

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);
}

Page State in Windows Phone 7 applications - do I need to save it?

In the following blog post the author describes the need to store page state, e.g. the text within a TextBox control, in the Page State dictionary so that it is restored when navigating between pages:
http://www.wintellect.com/CS/blogs/jgarland/archive/2011/01/26/a-matter-of-state-part-1.aspx
However, I have created a very simple application that has one page with a Button and a TextBlock and a ListBox of items. The button navigates to a dummy page, via NavigationService.Navigate. Now, if I scroll the list and input some text into my TextBox, navigate to the dummy page, then hit the back-button, I can see that my text is still present in the TextBox and the scroll position was preserved.
My question is, (tombstoning aside) do I ever need to persist the state of UI controls when simply navigating between them? It would appear that the frameowkr does this for me (despite the blog post above!).
You should persist state if it makes sense in the context of your application and will be helpful to the user.
This almost certainly means when tombstoning but probably not when the application is closed via the back button and then restarted.
In your scenario, the scroll position and text will be lost on tombstoning so you probably want to save these details.
Saving state is only relevant in the context of tombstoning and launching new instances of an application so (a tiny number of exceptional cases aside—and it doesn't sound like you are one of them) it doesn't make sense to talk about saving state outside of this.

OnBackKeyPress going to another instance of a page

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.

Getting Windows Phone 7 WebBrowser Component VerticalOffset

I want to persist the user's location in the document he or she is browsing, then bring them back to that spot when they return from tombstoning or between sessions.
My first approach was to wrap the browser component in a scrollviewer, but it turns out it handles its own scrolling and the scrollviewer never changes its verticaloffset.
My guess is that the browser component must have a scrollviewer or something like it embedded in it. I need to get the verticaloffset and scroll to an offset.
Any guesses how to get there?
My next approach would be a painful mish-mash of javascript and c# to figure out where they are...
Because of the way the WebBrowser control is built you'll need to track scrolling in Javascript then pass the location to managed code to handle storage of that value.
On resuming you'll need to have the managed code pass the scroll position to a Javascript function to reset the scroll position.
That's the theory but I haven't looked at the funcitonality around javascript scrolling events in the WebBrowser yet. That's the only place I can see possible problems.
Would be good to hear how you get on.
I've accepted Matt's answer, but I want to put in some details here. I'm also going to blog about how I did it once I'm completely done.
Since the WebBrowser component is essentially a black-box, you don't have as much control as I would like. Having said that, it is possible to get and set the vertical offset.
Javascript lets you ask for the value, but different browsers use different variations on HOW to ask. For THIS case I only have one browser to worry about.
First I make a couple of simple javascript functions:
function getVerticalOffset() {
return document.body.scrollTop;
}
function setVerticalOffset(offset) {
document.body.scrollTop = offset;
}
Next I call into the WebBrowser using the InvokeScript method on the browser object.
I'll post an update here with a link to my blog when I get the full write-up done.
I have been writing an eBook reader and had a similar question. Code for setting a scroll position has been easy enough to find.
Code for setting vertical scroll position:
string script = string.Format("window.scrollBy(0,{0});", "put your numeric value here");
wb_view.InvokeScript("eval", script);
Google didn't help much in finding solution for getting the value of current scroll position. Lacking any knowledge in javascript it took me almost two hours to get it right.
Code for getting the vertical scroll position:
var vScroll = wb_view.InvokeScript("eval",
"var vscroll = window.pageYOffset; vscroll.toString();");

Resources