I'm developing a windows phone app, one of my pages use a panorama that loads a bunch of UIElements, taking a good share of memory.
Since every time I navigate to that view the page is created all over again, is there any way to reuse the page instance? Or there is any other way to ensure that the UIElements aren't created more than once?
EDIT:
The navigation process is the follows:
HomePage -> Secundary Page
Back
HomePage -> Secundary Page
Back
HomePage -> Secundary Page
etc.
What I want is that the secundary page instance to be reused after the first navigation.
Thanks
PhoneApplicationPage's lifecycle is completely managed by the runtime, you cannot influence it in any way. If user goes back from the page, it will be re-created next time. See this document, "The OnNavigatedFrom Method" section.
In fact, if you absolutely want to keep secondary page in memory, you could override normal back button behavior on the secondary page, and instead of going back to main page, you'd go forward to the main page. Of course, you'll have to keep the backstack in order, to avoid side-effects mentioned in KooKiz's answer.
Note that it's still not guaranteed that secondary page will stay in memory, since it's up to garbage collector to decide. The more memory page consumes, the better candidate it is for GC.
The problem is how you get page to the main page after navigating to a secondary page.
My guess is that, from the secondary page, you're calling:
NavigationService.Navigate(new Uri("/MainPage.xaml", UriKind.Absolute));
This is wrong, for two reasons:
As you noticed, you'll create a new instance of the page each time, and therefore use large amounts of memory
To exit the application, the user will have to press back as many times as they navigated to the main page
Instead, since the main page is still is the navigation stack, just call GoBack from the secondary page to re-use the previous instance of the main page:
NavigationService.GoBack();
Related
If there is no mistake:
React-Router's <Link/> component can carry over data (state) when the user doesn't leave the current tab or you force the user to open new tab on left click using target="_blank". Otherwise the state you send with it is lost because we'll have a new empty history stack.
localStorage can be used to share state between tabs but it's problematic in scenarios where i just want to store the data for only the regarding tab user is expected to navigate.
e.g. I want to set a state using the state/data I've stored for that specific tab and doesn't want to store it anymore/ forget about it. In this case, synchronization problems may occur when the user actually creates multiple tabs using the same <Link/> component but doesn't navigate to all of them. How?
Say, I've removed the state item from the storage when the component is unmounted in one of the tabs user is already navigated and, later on the user is navigated to another tab expecting the item in the storage to set the state. (The component in this tab will try to set state with non-existent data / will crash.)
I could hold the state till the window's onunload event is fired at best, but the problem still exists because localStorage is shared across all of the tabs and removing an item affects all the tabs like i've mentioned. ~ I have to remove the items somehow, can't rely on storage of 2MB to 10MB forever. I tried to find other solutions like clearing it once in a while on user logout/login but that would force the user to take those actions again, once in a while.
So I want to be able to store selected the state/data on sessionStorage of the newly instantiated tab and it gets cleared for me when that tab is closed and I don't have to deal with the regarding problems.
The problem could be defined with simpler words as:
I want to send a piece of data from one tab to another with empty history stack in the scope of only that tab.
Because I don't need it anywhere else.
I can do things like setState using that data, remove that data etc. and the other tabs launched in need of that data don't get affected.
I've searched through the other questions but there are not detailed answers covering this scenario or I couldn't come across with a best practice for this kind of stuff using ReactJS. Sorry If this is a duplicate.
I'm using ui-router.
A similar question has been asked on this a Number of times... But the solutions seem to be all over the place and either the question doesn't address a simple idea or the answer doesn't, either.
Here's my simple ui-view setup:
A master view has the navbar and footer
Children of the master view/route that can be activated include the Homepage, About Us page and Learn More page
Pretty simple...
By default, if the homepage is activated, and scrolled down 500px, and I click on a route to the "About Us" page, that page will be scrolled down 500px. Obviously this is not desired.
So... Everyone's solution is some variation of setting document.scrollTop(0) on every state change success. This is atrocious.
While it fixes the issue at hand, it clobbers the browser back button behavior. Here are some problems:
When a refresh is called, the standard browser behavior of refreshing to the current location is ruined
When the back button is clicked, the homepage would then scroll all the way to the top
If the back and forward button were clicked, I wouldn't retain the correct spot on the next page, either
This whole document.scrollTop(0) or any variation of it, really doesn't seem to be viable and I've yet to see a clear solution to this.
I am trying to build an app using Extjs 4.1. In general: it is a viewport with a tree panel on the west and a center panel that it is actually a tab-holder panel. When a user clicks on a tree node a tab is populating the center view. I had set an attribute in the tree panel that after selecting a node it gets deselected (deselectAll). The reason for this is that the user can open many tabs from different places (e.g. within each tab). But, when I set the above attribute it is producing an error (the “data” is undefined). The data that is undefined is the data related to the tree node. So, the question concerning selection model:
How can I address this problem (a solution may be to select the fist node, but I don’t want it)?
As for the history utility, I need to implement browser back button. Especially I want to disable browser’s refresh button. If user opens let’s say 15 tabs and accidentally click on browser refresh or “F5” he/she will lose everything. I had tried many things but with no luck. I am unable to understand “Ext history util”. So,
Is there any good example out there?
Could anybody guide me on how to do it?
Notice that the application is built respecting the new “MVC” architecture.
Stopping the refresh event is pretty easy - providing that your page has the focus. E.g.:
Ext.getDoc().on('keypress', function(event) {
if (event.getCharCode() == event.F5) {
event.stopEvent();
console.log('you stopped the refresh event');
}
});
If your page doesn't have the focus then there is nothing that can be done -- but most of the time your page loses the focus when a different browser tab is opened so F5 would be refreshing that one instead anyway.
I'm still trying to wrap my wits around the first part of your question, but I thought I would share that.
EDIT
Instead of trying to stop the default browser behavior (something which you can only do on a very limited basis), you should look into state management. ExtJS supports it on many components. Here is the ExtJS example.
Also here is the example of controlling browser history.
I should create ExtJs4 app, which should have main menu, and each menu item should open a new page with different url, so if the user copies the url and pastes on other browser tab, the app should open that menu item.
I want to use ExtJs's recommended MVC architecture, but I don't know how I can use it with multiple pages/urls. All their examples are using single page.
One option is to reload the page each time when the user clicks on particular menu Item, so every url/menu item/page will be separate ExtJS app with it's MVC. But I think this approach has drawbacks, since the page will be reloaded every time and it's not good for performance. Also it's causes difficulties in reusing of components (common models, stores and views for different pages ).
So I would like to have one single app for all pages, but I don't know is there any solution to have different urls for different views (in my case: for different menu items).
Or is there another approach for such applications?
You would probably want to use a Viewport, and make the Center Region a Container.
The Center Region Container would usually have a Card or Tab layout.
When the user navigates to a new view (Component), you add that view to the Container, and make it active.
The big mistake is to change the URL first. You don't want to do that.
You want to navigate, and then set the URL if the navigation was successful. You should probably not use ExtJS's History component, as it is incorrectly implemented. I would recommend using HTML5 pushState.
You should make sure your navigation system works without changing the URL bar too.
I would recommend reading up on Navigation in Microsoft Prism, WPF, and Silverlight, as there is more documentation there, and then apply that to ExtJS.
http://msdn.microsoft.com/en-us/library/gg430881(v=pandp.40).aspx
Here is an example Navigation process:
call app.requestNavigate('contacts/5'); you would add this yourself.
you parse this fragment to:
navigationContext = {
fragment: 'contacts/5',
xtype: 'contacts-form',
parameters:{
id: 5
}
}
OPTIONAL: If using forms:
get active item from the navigation region (your center region). if exists, call confirmNavigationRequest(callback) . you will need to add this method or event.
if callback(true), proceed with the navigation. this allows the user to cancel a navigation, if say the form is "dirty"
END OPTIONAL
the easy way is to then create a new widget of navigationContext.xtype, add it to the navigation region, then call setActiveItem(widget). destroy the previous active item if it existed.
then call history.pushState(null, null, navigationContext.fragment)
then raise a 'navigatedto' event on the view, passing the context, and you can load the data from there.
More advanced scenarios include:
keep the previous component alive if you expect to return to it. add a keepAlive property and if true, don't destroy when add new components to container.
search the container and ask each component if it wants to handle the current navigation request (for example if a form loaded with contact-5 was already hidden in your navigation region, or if you want to re-use a form)
I have a really strange issue relating to how I handle navigation in an application, and that application now being rejected from AppHub (after being successfully approved a number of times on the same code base... grr)
currently I am capturing the first navigation of the application and routing it an "add item" page in the App.cs using the example found here
the user then adds an "item"
the user is taken to the "main" page again, but stay there are there is now 1 "item" to show in a list
the user then can view a "detail" page of this item where they can select to delete the current item. when they do that I redirect them to the "main" page again.
this navigation then fires the same thing that happened in step 1
and they are routed to an "add" page
the problem with the above process, is that if the user hits "back" on the routed page in step 5 they don't go anywhere as they are routed back to the current page (because there are no items on the page previous and this fires the app.cs routing event to take them to the add page). if I did allow for them to go back, the actual first page they would be able to go back to is 3 nav steps back, when they first added the item - as they are on the "add item" page already, this would be pointless.
The apphub store testers say that in this instance, the application should close. I really don't know how the f&*k I am meant to make this happen, as there is no "go back until close" action I can call...
thoughts?
When the user decides to "delete" the current item, you shouldn't navigate forward to the main page, leaving the deleted item in the navigation stack. You should navigate back to the main page. That way the navigation stack will be empty, and if they navigate back again, the app will close.
(The same is true at step 3, of course - when the item is added, navigate back to the main page. You don't want the "add" page as part of the navigation stack; that action has been completed.)
The single best advice I read on WP7 navigation was "if you don't have to, don't use it." I've almost stopped using it all together and just use "MainPage.xaml" for loading/unloading user controls that do this kind of stuff. I completely control the Back button as needed. It has saved me so much headache. The important thing to realize is that the Navigation pages are really just mimicking a website and it's pages - many apps do not fit that paradigm (as they are apps, not websites). So, if you don't have to use Navigation, don't use it.
So in your case, if you just managed everything on MainPage.xaml, you would use a number of If/Then statements in OnBackKeyPress and if one meets your criteria, do an e.Cancel = true; and show/load/etc. your thing. If not, let the app navigate out of itself - i.e. exit.
For tombstoning, just let the OnNavigatedTo in MainPage.xaml handle loading the right user control received from tombstoned information retrieved from Application_Activated.