-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
Navigation data is retained and also presented to IQueryAttributable on Back navigation. #10294
Comments
Code to reproduce 10294 dotnet/maui#10294
I've added a link to a GitHub project/branch with code to demonstrate the issue. Note that I'm not sure how this would end up behaving for Deep navigation (pushing multiple pages). It would seem that the workaround of clearing the query data would end up removing data required by lower/child pages. Thus you'd need to selectively remove data on each page. Which is less convenient. |
@bakerhillpins if I'm following you correctly this is by design if you have 3 pages page1 => page2 (with a query parameter) => page3 If the user hits the back button then they want to return to page2 with the state that page2 was at when they navigated away. If you want page2 to change after the user has gone to page3 then I'd recommend wiring into the "NavigatingTo/From" events to modify page2 or you can clear out the query parameter "..?Bear=" |
Hi @bakerhillpins. We have added the "s/needs-info" label to this issue, which indicates that we have an open question for you before we can take further action. This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time. |
@PureWeen - I can't make sense of what you've written, sorry. I'll try to expand on what I'm reporting. First: public Task GoToAsync(ShellNavigationState state, bool animate, IDictionary<string, object> parameters);` are retained in memory with the page after the navigation operation completes. They are first wrapped in Second:
|
@PureWeen I've added code in the repro example to show the data being retained in the navigation hierarchy. As you navigate down it creates objects. You can force the GC to run but the objects are not released until you pop the page (navigate back). |
So after sitting on this statement for a while this doesn't happen, because when I return to page 2 it is presented with the query data that was active when we navigated TO page2, not when we navigated away. When we navigate to page 2 we present INITIAL data via the query dictionary. That state may be altered or deleted, or whatnot before we navigate to page3. So returning to page2 and being presented with the INITIAL query data again, doesn't retain page2's state when we navigated away, it changes it back to INITIAL conditions. |
I've also been experiencing this issue. When I navigate to a page with a query dictionary, I expect it to pass those params a single time so I can consume them and throw them away. However, when I push a new page on the stack and then navigate back, those same params that I've already consumed are passed into ApplyQueryAttributes() as if I had just created them again. It's very confusing. |
I'm probably still missing something obvious here Page1 -> Page2?ContactId=3 => Page3 If I'm on Page3 and hit the physical back button what query parameters should Page2 get? |
Nothing... But it get's ContactId=3 @PureWeen Have you tried the example project? |
We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process. |
Same issue. |
@Kaiffa Don't forget to remove/clear any passed objects at the end of the navigation ApplyQueryAttributes method (The workaround) if you are using it. MAUI is retaining them in the query dictionary and therefor your business object will NOT be garbage collected until after the page is popped from the stack. |
Any work around this issue ?, I have a slave page that return a bar code value to main page, if I scan code bar once and return that value to my main, that value still in the query, when I open my slave and close without scanning a bar code, the old value still in the memory, this behaviour is weird, main and slave are transient pages. |
A workaround for me : clear query dictionary after receiving it, I am able to do it in view model class that implement `public void ApplyQueryAttributes(IDictionary<string, object> query) } //clear the query to release the data
|
True, but what this issue shows is that "re-applying query parameters" does not restore that state (when navigated away), it restores the page's initial state. Can a page on nav stack retain its "current" state, so it can show it again? |
Personally I wasn't very surprised by this. It makes perfect sense if you're used to web development, and the MAUI AppShell navigation makes it abundantly clear. If on the web I:
It makes perfect sense to me that if I navigate back, I navigate to the exact page I requested, including the query. What actually baffled me, is that the same also happens when you use |
I have this exact issue, but put the barcode scanner in a modal, for reasons explained above. However I'm not willing to clear my query attributes, because having them there makes perfect sense to me. I think |
I've made #12630 to talk about the modal specific use case. |
I hear you but I don't agree because I'm not actually "navigating" to a new page as you describe above. The Pop/Back operation doesn't take in a
|
So I'm following up here because technically the my 1st bullet isn't drawing a proper analogy between the web example and MAUI. Though I used a navigation stack with multiple pages because that's what this issue is rooted in. Specifically, the web navigation pointed out by @Ghostbird would result in the following navigation stack changes on MAUI. /Page to /OtherPage and then /Page. At no point in that web example is a Navigation Stack built up. It's simply one page at a time at the root. And in that regard MAUI does work as he mentions. But the issue isn't about new pages at the root, it's when we move backwards through the navigation stack and so the web example isn't demonstrating the issue situation. And this brings up an important point. MAUI and Web applications are different tech stacks and they behave differently because of that. Outwardly they may use some of the same concepts like Uri based navigation but effectively the similarities end there. To my knowledge (which is limited in web) web applications don't remember/retain previous views and in that regard are stateless. Each request is completely new and thus each new page served up as the only one in existence. In fact the web app isn't rendering the view, the browser is. Thus, we shouldn't confuse navigation between webpages and browser back button behavior. The browser after all isn't the web application, it's what we use to view state. The Back button is a feature of the browser and is simply saving the previous view (the actual instance) on a stack and pushing/popping those saved LOCAL states back to the user.
It's unfortunate that you've splintered the conversation to #12630 because the situation you describe there IS in fact identical to this issue in that the user is navigating backwards through the navigation stack. The modal web example you provide is actually better aligned to what we have occurring in device based apps since the navigation is happening within the root view (it's instance isn't lost). |
Lets be clear here. It isn't "MAUI" (in general) that is behaving this way. It is specifically "AppShell". The behavior we see is specific to AppShell's design, which seems to me to be different than the mobile platform's native navigation paradigms. Its also different than Xamarin.Forms older navigation mechanism, NavigationPage. begin rant My view of AppShell is that its navigation paradigm is out in left field, for no good reason. I'm not a fan. This unexpected behavior is one of many that can be seen by searching StackOverflow for questions tagged Xamarin.Forms or Xamarin, and mention Shell or AppShell. Quite a few app devs have struggled to get this to behave the way they need. Read those questions; it clearly does not match most people's intuitions about navigation. By contrast, NavigationPage is a straightforward design. Straightforward, yet fully flexible, because it is easy to undersand what Nav stack is doing, and to programmatically manipulate it. AFAIK, never caused anybody serious problems. Still works great today in Maui. Just change one line of code: Of course you then don't have any of AppShell's features. Its a tradeoff. end rant |
Hi, yes I looked at that, but then I had another strange problem. It looks like the ApplyQueryAttributes method was only ever being called once. This is a problem for me because the issue is on the way back. I.e. : So when page 3 goes back to page 2, I am unable to get the query attributes. |
It's difficult to say what's going on without seeing how your navigation code is setup. Do you have a repo/code you can point to? |
I don't have one for this. To be honest i've reached the stage where i'm just looking for workarounds for all the problems now rather than reporting them. |
Here's my first go at addressing some of the complaints here. Let me know if you have any thoughts/suggestions/questions. Ultimately, I'd like to add a richer set of interfaces, but I think this is a useful modification for NET8 |
@PureWeen For my part in all of this it still seems odd to retain any parameters since the uri that's being applied to navigate back via |
Basically this. We're still discussing some other approaches for that PR. Possibly just adding a configuration property so you can disable the current behavior. We have to be careful about not breaking users that depend on aspects of this behavior (as confusing as it might be). The current PR was primarily proposing an approach with minimal breaking. One additional piece of information here is that the BP being used for the parameters was for hot reload. There are scenarios where a page might get recreated by hotreload, so the parameters need to get re-applied. It's unfortunate that bleed into the actual behavior so much but that's the background here. |
It drove me crazy. Here is my solution: ` [ObservableProperty] [ObservableProperty] protected override void OnPropertyChanged(PropertyChangedEventArgs e) |
I think you mean that the ellipses inside the You'd get something like this: public void ApplyQueryAttributes(IDictionary<string, object> query)
{
if (query.TryGetValue(nameof(Prop1), out var newProp1)
{
Prop1 = newProp1;
}
// To clear all route data
query.Clear();
} |
Yes, you are right, the effect would be the same.
|
Description
I'm using Shell with my MAUI app and am passing parameters during navigation with
Shell.GoToAsync()
using theDictionary<string, object>
and theIQueryAttributable
interface as discussed in the MS docs.I noted that my bindings and initialization code for the ViewModel kept being re-executed when I would Navigate Back to the parent page. It appears that any data that's passed as navigation parameters is retained in memory for the life of the page and is subsequently returned to that page during a "Navigate Back" operation. Overriding the back button operation with code that doesn't pass any parameters didn't change the result. Such as this:
Any attempt to clear or supply a different set of data via the method call simply serves to add to the already stored query data. Thus:
results in the "w" parameter being added to the current store of parameters. And now "w" and "Bear" are retained until the page is removed from the stack.
Maybe I'm used to external navigation paradigms but my presumption was that the data was transient for the life of the navigation operation only. Thus the retention of data was not expected. The docs fail to mention anything about the data being retained for the life for the page as well. Off the cuff this seems like a poor model as it increases memory footprint and possibly has unintended consequences if any system resources were shuttled as parameters.
Steps to Reproduce
Pass parameters to any page as you navigate down a hierarchy. When the back button is pressed the query data that was passed to any particular page on the initial navigation TO that page is returned via the IQueryAttributable interface.
Link to public reproduction project repository
https://github.com/bakerhillpins/Issues/tree/NetMauiIssue10294
Version with bug
6.0.486 (current)
Last version that worked well
Unknown/Other
Affected platforms
iOS, Android, Windows, macOS
Affected platform versions
Android 9.0, API 28
Did you find any workaround?
As the Query parameters are passed via
IDictionary<string, object> query
the author would need to manually cleanup individual resources withIDictionary<string, object>.Remove()
orIDictionary<string, object>.Clear()
in an implementation of theIQueryAttributable
interface:If one was using the Attribute:
they'd be forced to implement the interface to remove the data. Or, I suppose their property setters must qualify any update with a test for != or their bindings would re-execute when they returned to the page.
Relevant log output
No response
The text was updated successfully, but these errors were encountered: