Xamarin Forms and Prism, error when calling NavigationPage - c#

I'm trying to implement a login flow (firstly showing the LoginPage) and the Login Page has a Command that the user can click to create an account (this is a NavigationPage), so the flow is LoginPage -> NewAccountPage (with button bar to navigate back to LoginPage).
In App.xaml.cs I have:
NavigationService.NavigateASync("LoginPage"); //I'm not sure if the LoginPage should be in NavigationStack, maybe be presented in Modal way
In LoginPageViewModel, I have a Command that simply call
_navigationService.NavigateAsync("NewAccountPage");
When the user press this button to create an account, the NewAccountPage is properly called but I get an error when the code flow finish to call the NavigationAsync("NewAccountPage");
The error is something like this :
Unhandled Exception:System.InvalidOperationException: Sequence contains no elements ocurred
I have no idea how to handle with this, could someone review if I'm making any mistake?

NavigationService.NavigateAsync("/MasterDetailsPage/NavigationPage/MainPage");

Related

.NET MAUI: Switching the App's MainPage multiple times leads to exception

The root of a .NET MAUI application is the class App : Application.
This class has a property Page? MainPage that contains the current root page.
I try to use this property for navigation. I wrote a method App.ShowPage(Page page) that sets the property MainPage to the given page.
This works like a charm! I start my application and show a login page - works.
When the user clicks login on my login page I show the main view (a TabbedPage) - works.
When the user clicks on an item on that main view a details view gets shown - works.
Now when the user clicks cancel on that detail view, I try to navigate back to the main view. As always with my method App.ShowPage(Page page). Now I get an exception:
IllegalStateException; The specified child already has a parent. You
must call removeView() on the child's parent first.
So the error message tries to tell me what to do. And I do find properties like Element Parent or Element RealParent on the Page page I try to open - but they are all null. So how do I remove the page from that parent? What is the removeView() method in the .NET MAUI world?
Thanks in advance for any help!

Is it there an alternative to Navigation for Xamarin?

I working on an Android App using Xamarin.Forms. I have a few problems with the navigation.
When I use Navigation.PushAsync(new ContentPage()); my navigation flow creates bucles. When I press go back, I revisit pages that sould be inaccesables. For example I push this pages:
Login (go)> Menu (go)> CloseSession (go)> Login
When I click the go back button of Android, the flow is this:
Login (go)> Menu (go)> CloseSession (go)> Login (goback)> CloseSession (goback)> Menu (goback)> Login
insted of going out of the App:
Login (go)> Menu (go)> CloseSession (go)> Login (goback)> App close
I know if I use Navigation.PopAsync(); the last push page is remove from the navigetion stack but it look tricky for me. Is it there an alternative to Navigation for Xamarin? Some way to create navigate pages avoiding adding them into the stack?
I believe what you are trying to do is "manipulating the navigation stack".
If you don't want a page to be on the navigation stack you can remove it as soon as you navigate away from it using Navigation.RemovePage(page).
You can pass a saved reference of that page, or look it up in the Navigation.NavigationStack, if it's a known scenario (known navigation stack index of the page you want to remove) you can do:
Navigation.RemovePage(Navigation.NavigationStack[index]);
Or you can use InsertPageBefore() followed by a PopAsync() as shown in the navigation docs example:
These methods enable a custom navigation experience, such as replacing a login page with a new page, following a successful login. The following code example demonstrates this scenario:
async void OnLoginButtonClicked(object sender, EventArgs e)
{
if (IsValid)
{
Navigation.InsertPageBefore(new MainPage (), this);
await Navigation.PopAsync();
}
else
{
// Login failed
}
}
You shouldn't use navigation like this. Some forms (especially login), should be popped when completed.
Push login form
User Completes login
Pop login form
Decide which form should be pushed next.
In your scenario I suggest you use Modal Pages to present the login page .
It will create an extra modal stack which will not affect the original stack.
When user complete login , then pop the login page .
The flow
Set NavigationPage(root page : Main) as MainPage in App.
Show login page using PushModalAsync .
Complete login
Close login page using PopModalAsync.

Prevent user from returning to last activity

I am working on a Xamarin.Forms project, and in my PCL i created startup page called "Login.xaml". On this page a user has to fill in their credentials and sends it to an WebAPI. When the API returns "1"/true it opens a new page called "Home.xaml".
How can i prevent the user from returning to the login page when pressing on the back button on the phone? ie: The user logs in on the first page, webapi validates it and returns a "1" so the new page ("Home") gets opened, but when the user presses the Back button it returns to the login screen. This should not be possible until the app gets closed down.
You can remove the login page from the navigation stack when you're pushing your Home.xaml:
await Navigation.PushAsync(new Home()); // or whatever your page is called
Navigation.RemovePage(this);
This way there's nothing to go back to after your user gets to the homepage.
For this to work, your login page needs to be a NavigationPage. For this, you'll have to wrap it with the NavigationPage ctor:
// this goes into your App.cs where you enter your app:
public App()
{
MainPage = new NavigationPage(new Login()); // or whatever your login page is called
}
I suggest you have a look at the documentation: Introduction to Xamarin Forms - Navigation
As for me, calling RemovePage() was giving me all sorts of problems.
What I had to do is shift my thinking. If you do Pop instead of Push, you're actually removing the page for good. So what do you need to do in order to be able to do Pop instead of Push? Insert the next page before the current page first, and then Pop:
var newRootPage = new NewRootPage();
this.Navigation.InsertPageBefore(newRootPage, this);
await this.Navigation.PopAsync();
Note: for this to work you will also need to do wrap your initial root page in a NavigationPage like #germi says in the last part of his answer:
// this goes into your App.cs where you enter your app:
public App()
{
// or whatever your login page is called
MainPage = new NavigationPage(new Login());
}
PS: FWIW this was my fix in my F# open source project.

maintain login and logout sessions in asp.net web forms

I am trying to implement login and logout in asp.net(web forms). In my web form I have two pages namely Default and Main. From Default page when I login with username and password it redirects to the Main page. When I press back button it directly redirects to the default page. For this I copied javascript code to my default page
<script type = "text/javascript" >
function preventBack() { window.history.forward(); }
setTimeout("preventBack()", 0);
window.onunload = function () { null };
source from stackoverflow question
After login when I click on back button in my browser(chrome) first it shows the Default page and then it shows the Main page. i.e page blinks when I click the back button.
It shows main page successfully with the issue.
What should I implement to stop showing the Default page when I click on back button
Update:
<script type = "text/javascript" >
history.pushState(null, null, 'Default.aspx');
window.addEventListener('popstate', function (event) {
history.pushState(null, null, 'Default.aspx');
});
</script>
I placed this code in default page
There is one important thing that you ought to know here.
One cannot disable the browser back button functionality only thing that can be done is prevent it.
You can't, in anyway diasble that button. What you can however do, is to put some logic and prevent that button from doing what it is meant to do.
Now for the script that you have shown, it should serve fine and the other thing to try here is to put a mediator page between your default and main page. So when you login, the control will flow to mediator page and it will then redirect to main page. Now when the user presses back button on the main page, the control will flow to mediator page which will again redirect the user to his main page.
The effect will be the same as your script, but putting a page can help you write Session handling code and some server side checks if you want.
But one thing is sure, the browser back button will be as it is.
Hope this helps.
As Matt said you can't disagree the back behaviour. However you can check if the user is logged in and redirect them to the main page easily.
All you need to do is, on the default page check if the user is logged in, if they are then redirect them to the main page, this way even if the user clicks back, they will be taken back to the main page. And also the can go to the Default page after logging out.
Another way could be using location.replace("...."), which replace the existing document and user can't "go back" using back button as the page doesn't exist in the url history.
Src: https://developer.mozilla.org/en-US/docs/Web/API/Location/replace

How to resume the app with another page then the suspended?

I need to ask for a passcode every time the app was suspended (and resumed), so I have to show a corresponding page, and after the user enters the pin proceed the app resuming to the page which was shown before suspending. How can I get the page to which I have to proceed? The App.Resume event provides 2 parameters, but both of them are objects. To which type I need to cast these objects to get the proper page's type? Can I get from these parameters the proper page type at all?
I mean
private void OnResuming(object sender, object e)
{
//get the suspended page's type here
}
Thanks :)
I recommend the following:
In OnResuming simply Navigate to the passcode page, but remember the current page before.
OnResuming should look like this:
//...
// the following line returns something like e.g. "MainPage"
var pageTypeName = ((Frame)Window.Current.Content).SourcePageType.Name;
// store pageTypeName in app scope
// Navigate to passcode page ...
When passcode was entered correctly navigate to the previous page.
Second Option:
You can also try to navigate to the passcode page during "OnSuspending". The user will see the passcode page after a resume. After entering the code you can redirect the user to the previous page. Of course you also have to store the type of the current page during OnSuspending accordingly.
The code shown works fine if you have an "easy" interface without e.g. a SplitView. You probably have to tweak it a little if you are working with nested Frames etc.

Categories