-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Shell, Navigation and Page instantiation #9300
Comments
I have run into this issue as well, and it's a BIG one! I have had to resort to creating a "REFRESH PAGE" button at the top of each non-detail page, that executes the same code as the Constructor. This is the ONLY way I have found to get my data updated on the non-detail pages. PLEASE, PLEASE, PLEASE fix this ASAP. There is NO WAY that I'm going to release a Production app that requires my users to click a REFRESH PAGE button every time that they navigate to a non-detail page. |
I faced the same "issue", I ended up overriding the |
@angelru Thanks for the tip! |
Can you use |
@PureWeen - I tried OnNavigatedTo like you suggested. I put the following code into my StoreListPage.xaml.cs file:
And, I set a breakpoint and ran my App. |
@angelru - I tried your suggestion. I went into my AppShell.xaml.cs file and typed in the following code:
I got Compiler Error CS0115: no suitable method found to override By your message, it sounds like you got this to work. What am I missing? |
This code is from an application in Xamarin Forms, in .NET MAUI I have not tried.
|
@angelru - Using your example code, I was able to get it to work with just the following code added to AppShell.xaml.cs
Thanks SO much for your help! I STILL think that this is a bug, and that it should get fixed ASAP. |
Related #7354 |
@pfafft33 can you log a bug? From my tests it gets called. |
OnNavigatedTo is broken as soon as you have tabs within the flyout item, as per the example at the top of this issue. It works for the first tab, but not on any other tab, until you go to a different flyout item, and then back again, at which point the OnNavigatedTo will fire for whichever tab was previously shown. Certainly the case with both Windows and Android on latest preview downloaded on the date of this comment. |
You need to register your pages and the viewmodels associated with the pages as either Singletons or Transient in MauiProgram.cs. If regestered as Singleton the page is only instantianted once and the state of the page and the viewmodel is kept, where as for details pages for example you would use transient so its creted and destroyed each time you navigate to/back from it. Also use the EventToCommand behavior from the CommunityToolkit to call the pages "Appearing" and bind your code to a command in the viewmodel. Register the viewmodels the same as the pages in the MauiProgram.cs file. |
@AlexanderSCK It seems that when using Shell, the pages are reused even if using |
It seems like only the AppShell pages that has the routing attribute in xaml has this issue, if you do a second page navigation, the DI works as expected with the Singleton/Transient. Creating methods to perform the functions of the constructor is a workaround but not the best solution. |
Perhaps what is needed is a way OnDisappearing or a navigation event handler detecting "Pop" or "Go Back" to set a flag to indicate whether the view should be destructed or if it can be reused? On the positive side, navigation is much much quicker than with Stack based navigation from XF. Using good practices and not storing a lot of state in the views themselves helps. Using OnAppearing in conjunction with a call to your view model and ApplyQueryAttributes (from IQueryAttributable on the ViewModel classes) in should let reused instances reset themselves. |
I have a similar requirement in a new app, login page with registration flow, and then a list of pages under a tab menu. I have registered some pages and viewmodels under the tabs as Transient, and I expected that navigating to that pages they should reconstructed as new instances. This is because I can logout with a user, returning to the login page (setting it as root and clearing in this way the navigation stack), and relogging with another user, and I need that pages and viewmodels be reinitialized. But what I see at this time is that the pages and viewmodels are never recreated. I did not registered the route to this pages using the appshell.xaml, but forcing the route registration in appshell.xaml.cs (code behind). I found a workaround declaring a property in a baseViewmodel of each viewModel that I use to understand if call the Initialize method of each and resetting it from codebehind, forcing a sort of reinitialization when the page appears, but it's very tricky, and for use it I need to declare all the pages and viewmodels as singleton. |
in my situation I did not register the route from xaml but from code behind, but the pages are never recreated |
Then it might be a routing issue in general. seems like GoToAsync($"//{nameof(SomePage)}") the // is suppose to remove everything from the NavigationStack and in theory dispose of any Transient pages, but this does not happen. Having a look at MAUI Docs the wording use is "replace the navigation stack", maybe this should be the hint that it does not dispose on "replace"? @PureWeen - This is an issue if DI Transient Pages and ViewModels are not disposed. Do we perhaps have estimated fix, PR or Merge on this problem. |
It could be, but if you look in the Navigation stack after Navigated to the // page you can see that it just contains the root page. In the meantime I just created a sample to reproduce the problem, so if we are misunderstanding some concepts of DI or AppShell navigation somebody could help us, because I really can't understand if I'm doing something wrong, if I have a wrong expectation of if this is another bug of MAUI. In this app (that it's really raw because I just modified another repo created to reproduce a different bug of MAUI) the MainPage represent the LoginPage, pressing a button we navigate to a tabbed page, where the "OtherPage" Page is registered as transient as its viewmodel. I can see that the viewmodel and page constructors are called only once, then returning to the mainPage and after to the "OtherPage" I would expect to see new instances but it doesn't happen. Here is the repository: https://github.com/fgiacomelli/DependencyInjectionOnTransient |
Doesn't it make sense for views to be reused? In my opinion it would be faster for navigation. But ViewModels shouldn't be like this, since in them we get data and have changes to the views. But I understand that we can't have the view as a singleton and a ViewModel associated with that view as a transient, because this would also be a singleton. What would be the correct approach then? |
Sure that it makes sense, but like in any container we must be able to configure the classes registered as singleton or new on each request, and the architecture need to implement the correct behavior |
Sure enough, I have a page added in AppShell and I registered it as a |
Yea :-/ this was definitely a very unfortunate oversight. I think some users will want Perhaps just tying into Transient/scoped/singleton here is enough. If you register as Transient, it'll start you over if you don't it'll maintain the stack. No specific ETA on this, but I'm going to see if I can work out some helpers to enable the features here. Get some active feedback going! |
I've created a workaround using ServiceProvider class which is avaliable via DI in MAUI project. I've defined a generic TransientContentPage which resolves viewModel when OnAppearing event occurs:
This approach seems to work fine for me, still it is far from perfect. |
Verified this issue with Visual Studio Enterprise 17.8.0 Preview 5.0. Can repro on windows platform. |
I would appreciate if |
Any updates on when this is planned to be fixed @samhouts? |
this is true it happens only if we navigate using // to clear navigation stack. Trasient pages are clear out if we navigate without // |
Is there any updates on when this is getting fixed. This issue is two years old why is this not been made a priority. This is a showstopper for me and I'm guessing it is for many others. I tried @PureWeen solution like @pikausp did and same it creates strange behaviour. It initially did work until I tried to navigate back again to that same shell page the app crashes with unknown exception. This is a very hacky approach which i would like to avoid. If anyone has managed to figure out a solution that does work then please post. |
Add the following to AppShell.xaml.cs
protected override void OnNavigated(ShellNavigatedEventArgs args)
{
base.OnNavigated(args);
if (CurrentItem?.CurrentItem?.CurrentItem is not null &&
_previousShellContent is not null)
{
var property = typeof(ShellContent)
.GetProperty("ContentCache", BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Instance |
BindingFlags.FlattenHierarchy);
property.SetValue(_previousShellContent, null);
}
_previousShellContent = CurrentItem?.CurrentItem?.CurrentItem;
}
this code is working on Trasient Objects
…On Fri, Aug 2, 2024 at 8:36 AM Lucasian20 ***@***.***> wrote:
Is there any updates on when this is getting fixed. This issue is two
years old why is this not been made a priority. This is a showstopper for
me and I'm guessing it is for many others. I tried @PureWeen
<https://github.com/PureWeen> solution like @pikausp
<https://github.com/pikausp> did and same it creates strange behaviour.
It initially did work until I tried to navigate back again to that same
shell page the app crashes with unknown exception. This is a very hacky
approach which i would like to avoid. If anyone has manage to figure out a
solution that does work then please post.
—
Reply to this email directly, view it on GitHub
<#9300 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/ADL4WTOCZYEZYBPPOEJG3H3ZPOROHAVCNFSM56CUUIX2U5DIOJSWCZC7NNSXTN2JONZXKZKDN5WW2ZLOOQ5TEMRWGU3DMMJVGI2A>
.
You are receiving this because you commented.Message ID:
***@***.***>
|
@robertogonzalezdelarosa Yeah this is the solution I have already tried and is not working for me on version 8.0.70 - It would be nice to get a two year old problem fixed, not to hack it in. |
Yeah me too, but this solution was a lifesaver because I need it for my
work
…On Fri, Aug 2, 2024 at 9:04 AM Lucasian20 ***@***.***> wrote:
@robertogonzalezdelarosa <https://github.com/robertogonzalezdelarosa>
Yeah this is the solution I have already tried and is not working for me on
version 8.0.70 - It would be nice to get a two year old problem fixed, not
to hack it in.
—
Reply to this email directly, view it on GitHub
<#9300 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/ADL4WTNVUDMMGQLTPG4V2ETZPOUY5AVCNFSM56CUUIX2U5DIOJSWCZC7NNSXTN2JONZXKZKDN5WW2ZLOOQ5TEMRWGU3TCMJXHEYA>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
I have reported similar issue around the disposal of View and ViewModels +2 years ago like you can see here: |
What is the state of these related issues: |
It has been +2 years since I've reported this bug for MSFT and they didn't come up with a proper solution, so to save your precious time consider completely ditching MAUI AppShell for now, and use the following library to workaround this issue: |
This is a great solution, but is just what I was afraid of. Our previous App in Xamarin we were using Prism but decide for Maui we would drop that and start using Shell. We also have done the same and copied from Prism the functionality we need but using both the Shell and Stack Navigation in a NavigationService.cs, which I see you've gone that step further using Navigation page and removing AppShell. It's a shame cause it was going quite well. I found out early on the issue with the memory leak on the stack - pages not being removed/cleared #12354 so I decided to adopt both. To home screen via a login/landing view I navigate Shell.Current.GoToAsync and we have various paths of navigation via the stack Push and Pop, which as the shell navigation replaces the stack it was the cleanest way to clear the stack without getting unknown exceptions, when going home. We have a new feature in this App that allows us to update the style of the App, by logging out and back In again. This works great but as the shell navigated pages/views only instantiate once in the lifetime the new updated style of course will not change. The constructors of the view and it's viewmodel need to be hit every time. |
Any updates on when this is planned to be fixed @samhouts? |
This is done for NET9 if you register your pages as transient it will recreate them |
Any chance it could be put into .NET8, or are there no more planned releases before .NET9. We were not going to bother with 9 as it's standard term support and wait for 10. |
@Lucasian20 There is no such thing as standard term support in MAUI. You should always update to new version to keep up to date with iOS/Android API. |
Discussed in #5810
Originally posted by ioiooi April 4, 2022
Hello,
are Pages that are defined in the visual hierarchy only ever instantiated once? And if that is the case is there a way to clear the cache and force the creation of a new Page instance the next time I navigate to it?
For example the following hierachy is described in a
AppShell.xaml
:The LoginPage constructor gets called when the App is started. Navigate to the AboutPage with
Shell.Current.GoToAsync($"//{nameof(AboutPage)}")
and its constructor gets called.Now lets say the AboutPage has a Logout-Button which does some things and at the end it calls
Shell.Current.GoToAsync($"//{nameof(LoginPage)}")
. The LoginPage constructor does not get called. Navigate back from the LoginPage to the AboutPage and its constructor also does not get called.The same deal if I would navigate from the LoginPage to the SecretPage. The constructor of SecretPage would only get called the first time.
Lets say I use ViewModels for all those Pages. I can't really create a state in the ViewModel constructor because the Page only gets instantiated once and so in my case the ViewModel also only gets instantiated once. I would need to do the work in a OnAppearing.
I would want for the Pages after the LoginPage to always be newly constructed in order to make sure that theres a clean state.
PS:
A lot of examples also contain DetailsPages... something like ItemsDetails, MonkeyDetails, CatDetails etc... Those Pages are never declared in the
AppShell.xaml
but are registered like soand from what Ive seen seem to be always instantiated every single time theyre navigated to.
Workaround
#9300 (comment)
The text was updated successfully, but these errors were encountered: