Slow navigation between pages - c#

I am developing an app for Windows Phone 8 in VS2012 and My StartUp Project page is SetProfile.XAML which creates the profile for the first time, but if the user is entering the app second time, the page must not appear because there is already an existing profile.
So I have this code for the "Loaded" event handler, which checks if there is a created profile and if there is, navigates to MainPage page.
private void PhoneApplicationPage_Loaded_1(object sender, RoutedEventArgs e)
{
if (Flag.Contains("true"))
{
if (IsolatedStorageSettings.ApplicationSettings.Contains("player1"))
if (!(Flag.Contains("false")))
NavigationService.Navigate(new Uri("/MainPage.xaml", UriKind.Relative));
}
}
The problem is when I enter a second time, I see a blink of the SetProfile.XAML page then it navigates (it's like milliseconds), but I still can see it.
Is there any way I can make it faster so the user won't see it?

There is a very good blogpost about how to 'navigate' to a screen that is not always needed up on Shawn's blog here http://www.visuallylocated.com/post/2012/06/18/Using-a-custom-UriMapper-to-navigate-to-a-login-screen.aspx
The trick is to use a custom UriMapper class that checks all the info and determines the correct navigation uri.
You use this class in your app.xaml.cs - Application_Launching and Application_Activated

you see blink as you have used "Loaded" event,it loads page in run time and must not used unnecessary.
You must use "OnNavigatedTo" event for these normal scenarios.

Related

Implementing Tab-like Navigation model in Windows Phone 8 — How?

I am currently trying to implement a navigation scheme that closely resembles that of the Internet Explorer app on Windows Phone 8.
The IE app can have multiple tabs that the user can switch between. Each of these tabs has its own history. Hitting the Back Button on the phone takes you to the previous page in that tab's Navigation history (Not the PhoneApplicationFrame.BackStack). If there are no previous pages, the back button takes you to the previous opened tab or, if none, exits the app.
Why this is troubling me
Application.RootVisual can only be set once. So you can't have two PhoneApplicationFrames, each with its own BackStack, to swap RootVisual between the two.
You cannot traverse the BackStack (it is a Stack, after all). Can only call GoBack(). Calling GoForward() will throw an Exception.
PhoneApplicationFrame.GoBack() removes entries from the BackStack which can only be added again through the PhoneApplicationFrame.Navigate(...) method. So, manipulating the BackStack is a no-go.
Bright Ideas
Keep a Dictionary<enum, List<string>> which is updated with each call to a custom NavigationService.Navigate(tabTypeEnum, uriString, params). This will keep the Navigation history for each tabType, allowing us to possibly Navigate through the current Tab's history when the BackKeyPress event is handled. Bad thing is, calling Navigate(...) to go to previous pages (instead of GoBack) will add to the BackStack. So requires maintenance that hurts my brain right now.
Create a custom NavigationAwareTabPage : PhoneApplicationPage, which keeps track of its own navigation history and fakes navigation by animating a transition when its Content is changed. The only time we call a true Navigate is when we switch from one tab to another. (I think this is what the IE app does.) And the BackKeyPress would have to look like below.
This:
void RootFrame_BackKeyPress(object sender, CancelEventArgs e)
{
var rootFrame = sender as PhoneApplicationFrame;
if (rootFrame.CanGoBack)
{
// Get the NavigationAwarePage
var navAwarePage = rootFrame.Content as NavigationAwareTabPage;
if(navAwarePage.CanGoBack())
{
// This method "navigates" to the next page
// by changing the navAwarePage.Content
navAwarePage.GoBackToPreviousPage();
e.Cancel = true;
}
}
}
Has anyone been down this road?
All the magic of how ReactiveUI overrides the Back button is here:
https://github.com/reactiveui/ReactiveUI/blob/master/ReactiveUI.Mobile/WP8AutoSuspendApplication.cs#L91
The way that this works in ReactiveUI is that there is a content control named RoutedViewHost that is listening to the Back being signaled (you can do whatever you want in response to the hardware Back button and cancel the default action). ReactiveUI maintains its own ViewModel-based back stack and manipulates that instead of using WP8s, and you never call WP8s navigation methods.
This effectively means that, from WP8's perspective, there is only ever one page in the entire application. WP8 really wants to create that page itself, and it's specified in WMAppManifest.xml.
Don't try to participate in WP8's Frame system, it really wants to work its own way and you won't be able to convince it otherwise.
One last important thing, if you're at the bottom of your back stack, you must allow the default Back action to happen (i.e. what WP8 wanted to do, take you out of the app). Otherwise you'll probably fail Certification and you're Doing It Wrong™.

Override BackKeyPress in a classlibrary, is that possible on WP8?

I pass a PhoneApplicationPage instance to a classlibrary, and popup an usercontrol in this classlibrary, when I press back button, the whole application exit. Yesterday I sovled the problem in an application, but I cannot use the method in this classlibrary case.
I tried to subscribe to the event(BackKeyPress), but VS2012 says "parent_BackKeyPress" "System.EventHandler" override and delegate cannot match. I checked, they match.
PhoneApplicationPage mContext=...;
mContext.BackKeyPress += new EventHandler(parent_BackKeyPress);
void parent_BackKeyPress(CancelEventArgs e)
{
ppChangePIN.IsOpen = false;
Application.Current.RootVisual.Visibility = Visibility.Visible;
}
anything incorrect here? plus, can I use navigationservice in classlibrary? I did this before to navigate to a page created in the classlibrary like below, well it ends up crashing. Some say can't use pages in classlibrary, instead we should use Popup(usercontrol).
mContext.NavigationService.Navigate(new Uri("/ChangePINPage.xaml", UriKind.Relative));
I have successfully done just that:
// or some other method of accessing the current page
// - but via Application, to which you have access also in class library
var currentPage = (PhoneApplicationPage)((PhoneApplicationFrame)Application.Current.RootVisual).Content;
currentPage.BackKeyPress += (sender, args) =>
{
// Display dialog or something, and when you decide not to perform back navigation:
args.Cancel = true;
};
Of course you have to make sure that this code is executed if and only if the CurrentPage is the main page.
I also use Pages in class library. You can use NavigationService in class library: you can get it for example from current page obtained as above (currentPage.NavigationService). Or you could use the Navigate method of PhoneApplicationFrame:
((PhoneApplicationFrame)Application.Current.RootVisual)
.Navigate(
new Uri(
"/ClassLibraryName;component/SamplePage.xaml",
UriKind.Relative));
As the short Uris like "/SamplePage.xaml" will work in Application Project, to navigate to page in class library you have to give full location: "/ClassLibraryName;component/SamplePage.xaml".
But note, that if the application chooses to display message box to stop from exiting, it will not pass certification, as (from Technical certification requirements for Windows Phone):
5.2.4.2 – Back button: first screen
Pressing the Back button from the first screen of an app must close the app.

How to detect back button or forward button navigation in a silverlight navigation application

When a Page is navigated to in silverlight you can override this method.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
}
The NavigationEventArgs has a NavigationMode enumeration which is defined as
public enum NavigationMode
{
New = 0,
Back = 1,
Forward = 2,
Refresh = 3,
}
But calling e.NavigationMode always throws a NotImplementedException
Is there a way in silverlight to detect a page is being navigated to because the user hit the forward/back browser button.
What I am trying to achieve is some kind of state that can be preserved when the user hits the back button.
For example assume you have a customer page which is showing a list of customers in a datagrid. The user can select a customer and there is a detail view which shows all the orders for that customer. Now within an order item you can click a hyperlink link that takes you to the shipping history of the order which is a separate page. When the user hits the back button I want to go back to the customers page and automatically select the customer he was viewing. Is this possible at all ?
I also tried out the fragment navigation feature
NavigationService.Navigate(new Uri("#currentcustomerid="
+ customer.Id.ToString(), UriKind.Relative));
when the customer selection changes but this adds too many items to the history when the user clicks various customers on the customer page.
EDIT
There is also an method you can override
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
}
which is the same as handling the NavigationService.Navigating event as indicated by BugFinder's answer. In this method e.NavigationMode always returns New when when you hit the Back or Forward Button. The only time this method returns Back is when you explicitly call NavigationService.GoBack()
The
public enum NavigationMode
{
New = 0,
Back = 1,
Forward = 2,
Refresh = 3,
}
applies to the Navigating event..
if I do
_ns.Navigating += ns_Navigating;
void ns_Navigating(object sender, NavigatingCancelEventArgs e)
{
if (SecurityCheck(e.Uri.OriginalString)) return;
e.Cancel = true;
ShowError("You are not authorised to view this page");
}
I can see there that e.NavigationMode is set. You could do your test there?
I don't think there are any easy ways to do it out of the box, as far as I know.
What you are trying to achieve can be easily done using a framework I created at
http://ultimateframework.codeplex.com
What I have done is to mesh the silverlight navigation frame and prism navigation together, so you will need unity and prism and mvvm friendly.
What you want to achieve can be done using the framework in the following ways
1) Implement IsNavigationTarget and returns true --> which will keep the same instance when navigating back, therefore, keeping the selection/selected item.
2) Access the onnavigatedto's journal to track where you came from, say /item/1 was the previous stack, so you know back button has been pressed from item 1.
3) You can even implement your own back/forward/refresh within the custom control provided for achieving the same result (not in codeplex yet)
I actually use it for production code at work, and I created it, so please feel free to try it out. Note that the version on there is buggy, and I have yet to have time to release our latest build, but should you require it, I will update it for you :), just pm me.
Set a variable in the usercontrol containing the contentframe which indicates what customer is active.
Add a handler for the contentframe's Navigated event in the usercontrol. Use this to check the variable indicating what customer is active (if the variable is not null), and to select the customer.
This might be what you are looking for:
http://jakkaj.wordpress.com/2008/09/08/control-silverlight-by-using-browser-back-and-foward-buttons/

Hide elements in a web page whilst using a web-browser control for WP7

I am currently working on an app for WP7 for my university, and need a temporary solution to a problem. Now this solution is, that I will be loading a webpage using the web browser control for WP7. For example: http://m.iastate.edu/laundry/
Now as you see on the webpage, there are certain elements I want to hide, for example the back button. For now, what I have done to handle the back button is something like this:
private void webBrowser1_Navigating(object sender, NavigatingEventArgs e)
{
// Handle loading animations
// Handle what happens when the "back" button is pressed
Uri home = new Uri("http://m.iastate.edu/");
// The the current loading address is home
// Cancel the navigation, and go back to the
// apps home page.
if (e.Uri.Equals(home))
{
e.Cancel = true;
NavigationService.Navigate(new Uri("/MainPage.xaml", UriKind.Relative));
}
}
Now that works beautifully, except for the part that there is a back button on the hardware.
So my second option is to completely hide the back button ONLY on that page, and not its children. So not on http://m.iastate.edu/laundry/l/0
I am still debating on just parsing the data and displaying it in my own style, but I'm not sure if that's completely needed seeing how the data needs constant internet service and is already in a well-put format. Plus, I feel like that would be a waste of resources? Throw in your opinions on that too :)
Thanks!
You should inject a script in the page with InvokeScript.
Here is the kind of Javascript code you need to remove the back button:
// get the first child element of the header
var backButton = document.getElementsByTagName("header")[0].firstChild;
// check if it looks like a back button
if(backButton && backButton.innerText == "Back") {
// it looks like a back button, remove it
document.getElementsByTagName("header")[0].removeChild[backButton];
}
Call this script with InvokeScript:
webBrowser1.InvokeScript("eval", "(function() { "+ script +"}()");
Warning: IsScriptEnabled must be set to true on the web control
If the removal of the back button depends of the page, just test the navigating URI in C# and inject the script if neeeded.

Skip a page when the back button is pressed, WP7

In the current released version of WP7 you have no programmatic control over the page stack.
I start at A, go to B, and then C. B is the data entry page for new items, so coming back from C I want to logically land at A. Currently I listen for navigation on B that comes from C and force another back onto A. However, the event doesn't happen soon enough to stop the page from displaying on-screen.
A -> B -> C
C -> A
A is the top level list page. B is the new item page. C is the item detail page.
This only occurs on one form so far so my workaround is to override OnNavigatedTo in the page I want to skip, and call "go back" programmatically. However, this has the undesired effect of briefly showing the page and then immediately navigating off of it.
Is there a workable way to stop the flicker?
Should my workaround instead be to take full control of page navigation, including go backs? This will leave the page stack is a strange state, but that would be hidden from the user if I control all navigation.
I know there is a new feature in Mango to pop a page from the page stack programmatically, but I'm curious to know if there is a solution to the problem in the released version.
Another motivation for this is I don't know what version will be best to target, the latest, or the one that is just enough for the app. For the time being I'm sticking with the live version.
You should read this blog post on solving circular navigation issues and you can download this recipe code which demonstrates non-linear navigation.
I have stopped the flickering by making the root frame transparent for the duration of the skip. This example isn't straight from my code.
Firstly on the page you wish to skip, override OnNavigatedTo and test to see where you have come from (this is where my code gets specific, I keep track of where I am):
protected override void OnNavigatedTo(NavigationEventArgs e)
{
// If I've come from page C, go back again.
NavigationService.GoBack();
}
Secondly, in the main App.xaml.cs register an event handler for Navigating (I put it in public App() constructor):
RootFrame.Navigating += RootFrame_Navigating;
Finally, flesh them out to hide the frame and show it again for the duration of the skip:
private bool _skipped;
private void RootFrame_Navigated(object sender, NavigationEventArgs e)
{
RootFrame.Opacity = 100;
RootFrame.Navigated -= RootFrame_Navigated;
}
private void RootFrame_Navigating(object sender, NavigatingCancelEventArgs e)
{
if (_skipped)
{
_skipped = false;
RootFrame.Navigated += RootFrame_Navigated;
}
if (e.NavigationMode == NavigationMode.Back &&
e.Uri.OriginalString.Contains("ThePage.xaml"))
{
RootFrame.Opacity = 0;
_skipped = true;
}
}
The code to determine when to make the page transparent is also different in my actual code, but I've added an implementation to the answer for illustration. This is almost identical to the code in the recipe linked in another answer, but doesn't involve needing to use a third party DLL.
I provided my own answer because I've seen the sources provided in the other answers before, but never paid attention to the code for hiding the root frame. I am not using the Non-Linear Navigation Service, just the code fragment for frame transparency (I don't need it to detect circular navigation as I'm well aware of the design choices I make in the app and can spot them myself :-)
This suffices as a workaround in the (currently) one case I have where I need to skip a page that doesn't make sense when going back. I'd like to think when Mango comes out I will be best placed targeting the latest version, so this code will soon be defunct.
Sources:
App Hub code recipe for Non-Linear Navigation
Non-Linear Navigation Service Blog Post
There is no way to do it before Mango, except with the flickering way you already know.
In Mango, you can use NavigationService.RemoveBackEntry.
And it's more a question of a bad application design, than anything else. You shouldn't require a immediate page for anything.
Your workaround should be to design a application structure that doesn't require any immediate pages.

Categories