Why does OnAppearing not fire every time in Android - c#

I have a Xamarin project. When I run in UWP OnAppearing initially fires once and then loads the Login Page. After successfully logging in, my Main page fires OnAppearing again and I load data into my ViewModel.
However, if I run the project in Android, OnAppearing only fires once - When the Main page initially loads.
protected override async void OnAppearing()
{
if (!App.IsUserLoggedIn)
{
await App.NavigationService.NavigateModalAsync(PageNames.LoginPage, false);
}
else
{
((SchedulerViewModel)Schedule.BindingContext).LoadData();
}
base.OnAppearing();
}
Why does Android only fire once? Or is UWP the one misbehaving?

NOTE: NavigationService is not a standard Xamarin Forms class. I assume it is built on top of Page.Navigation.PushModalAsync and PopModalAsync.
This is documented behavior of Modal Stack on Android:
Popping Pages from the Modal Stack:
When PopModalAsync is invoked, the following events occur:
...
The page being returned to has its OnAppearing override invoked, provided that the underlying platform isn't Android.
NOTE: it seems to depend on the API version of Android. I just tested it on API 30, and Android did fire OnAppearing again, when modal page was popped.
Instead of code in OnAppearing, I would solve it like this:
In App.xaml.cs, instead of:
MainPage = new MainPage();
do:
if (!App.IsUserLoggedIn)
MainPage = new LoginPage();
else
MainPage = new MainPage();
Then when LoginPage is done, instead of pop modal, do:
Application.Current.MainPage = new MainPage();
NOTE: Adapt as needed, if these are pages inside NavigationPage or AppShell.

Related

C# Xamarin.Forms ios Navigation.PushAsync not working properly

I have xamrin.forms project with both Android and iOS. I have just simple 2 pages where i call one from the other. On android everything is working perfectly as it should but on iOS any call for forms (navigation.PushAsync, DisplayAlert, ...) is not working properly (does nothing) until I put application to the sleep (put it to the background ) and then when I reload it back everything starts to work perfectly.
This is how i create first page in App.xaml.cs
var page = new NavigationPage(new FirstPage());
MainPage = page;
Button command for my first page calls for this:
FormsNavigation.PushAsync(secondPage, true);
I allredy tried to wrap Push into Device.BeginInvokeOnMainThread but no result.
In Xamarin.Forms, when using a NavigationPage to navigate to a ContentPage, use await Navigation.PushAsync.
And, because all UI animations must be invoked on the Main UI Thread, I recommend wrapping it Device.InvokeOnMainThreadAsync.
async Task NavigateToSecondPage()
{
var secondPage = new SecondPage();
await Device.InvokeOnMainThreadAsync(() => Navigation.PushAsync(secondPage, true));
}

How to push pages to MasterDetailPage using Mvvm

I want to use Mvvm(Basic Mvvm) for MasterDetailPage development. But facing issue to push new ContentPage to Detail
If I am using code behind than no issue, I can do like below
private void Button_Clicked(object sender, System.EventArgs e)
{
Detail= new NavigationPage(new Menu1Page());
}
But when it comes to Mvvm in ViewModel I don't have Detail page access there. So I can this, but it is hiding MasterDetailPage
async Task Menu1Page()
{
await Xamarin.Forms.Application.Current.MainPage.Navigation.PushModalAsync(new Menu1Page());
}
So, how can push pages to Detail from Mvvm?
You can access Detail page too in ViewModel. Just you need to cast App.Current.MainPage as MasterDetailPage. Look at code below.
async Task NavigateNext()
{
await (App.Current.MainPage as MasterDetailPage).Detail.Navigation.PushAsync(new Menu1Page());
//(App.Current.MainPage as MasterDetailPage).IsPresented = false;
}
The above code snippet pushing pages as child of MasterDetailPage so that you can go back by pressing back arrow on Navigationbar.
You can set pages directly to Detail page, it shows pages at a first page of MasterDetailPage in this scenario back arrow wont be available to go back, like below
(App.Current.MainPage as MasterDetailPage).Detail = new NavigationPage(new Menu1Page());
//(App.Current.MainPage as MasterDetailPage).IsPresented = false;
By default, no.
You need to define BindingContext for the page, and use code-behind navigation.
Or use NavigationService, more details Enterprise App Navigation
Or use any Mvvm framework for this.

Cannot get MainPage in Xamarin.Forms to react/change

I have tried to different methods to get my MainPage to change and it is not happening. Basically when my App starts it needs to do some Async tasks to initialize everything, and then get the real main page to display. I first tried an event handler in App.cs. I can confirm the event handler does fire off in my debugger. However the code to switch the main page is not successfully doing so. Nothing changes in my UI. This code is below:
private void UnitStatusModelChanged(object sender, EventArgs e)
{
UnitStatusModel = _unitStatusMonitor.UnitStatusModel;
UnitStatusViewModel = new UnitStatusViewModel(UnitStatusModel, InputResourceHandler);
MainPage = new MainTabbed(UnitStatusViewModel, InputResourceHandler);
Debug.WriteLine("Switched page to " + UnitStatusModel.Version.Name);
}
protected override void OnStart()
{
_unitStatusMonitor.UnitStatusChanged += new UnitStatusModelChangedEventHandler(UnitStatusModelChanged);
_commandQueue.StartQueue();
}
I thought maybe setting MainPage this way is not the way to go. So I tried making the MainPage a blank NavigationPage, and then pushing a model page on top once the app is ready. This also had no effect.
var newPage = new MainTabbed(
new UnitStatusViewModel(_unitStatusModel, inputResourceHandler),
inputResourceHandler
);
App.Current.MainPage.Navigation.PushModalAsync(newPage);
I can confirm that if I start the app with a MainTabbed page, the page does display, so it should not be a problem with MainTabbed. Again, I also verified the in the debugger these lines of code are being executed with no exceptions being thrown. Still, no change to MainPage. What gives?
Check your thread after your async completes, when you call PushModalAsync (or any UI thing). Make sure it's on the main thread.

How to create a page in Code behind and navigate the main page to created page in Windows Store app?

I need to create a page in Code behind and navigate the main page to created page in Windows Store app
I tried this but its not working the black page is navigated
Page p1 = new Page();
p1.Content = pdfViewer1;
this.Frame.Navigate(typeof(Page),p1);
Navigating to a page created entirely in code behind is very tricky. I am not even sure it is possible to do (at least without some complex hack) This is due to the fact that Visual studio builds some classes behind the scene to ensure the navigation especially the class "XamlTypeInfoProvider" which is used to identify the pages to which navigation is possible.
According to me, the easiest way to navigate to a page created in code behind is to create a "normal" blank page and then to fill this blank page with content created in code behind.
// create the page content in code: here it is in the variable pdfviewer
this.Frame.Navigate(typeof(BlankPage1),pdfViewer);
and within the "blank page" use the OnNavigatedTo event to put the created page content on the screen
public sealed partial class BlankPage1 : Page
{
public BlankPage1()
{
this.InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
(this.Content as Grid).Children.Add( e.Parameter as UIElement);
base.OnNavigatedTo(e);
}
}
You'll need to make sure you're using the correct Frame object. From what you've provided, it looks like you need to use the "root" frame, much as is done when your main window is loaded in your app's OnLaunched override.
Here's an example of launching a secondary page from a main page.
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
Loaded += MainPage_Loaded;
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
rootFrame.Navigate(typeof(SecondaryPage));
}
}
Note that what you pass to Navigate is the type of the Page object, not an instance of it. Navigate will create an instance and navigate to it. The new page's Loaded handler can then connect up any additional content, such as the PDF viewer shown in your code. If necessary, you can pass arguments to the secondary page by using one of the other Navigate overloads.

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.

Categories