I have a Tabbed Page Xamarin Form application that I am trying to customize. I am migrating from an IOs only app to all platforms. In iOS there are a couple function that I used ViewDidDisappear(), ViewDidAppear() and ViewDidLoad();
The application today loads the tabbed page as follows:
{
Children.Add(new MyPage1());
Children.Add(new MyPage2());
Children.Add(new MyPage3());
Children.Add(new MyPage4());
}
Each of the child pages are declared as follows all inheriting from ContentPage.
class MyPage1: ContentPage
{
…
protected override void OnAppearing()
{
base.OnAppearing();
Content = SomeContentPage;
}
}
The problem that I am running into is that the OnAppearing() is called for all pages when only MyPage1 is currently displayed. I need to know when each child page is loaded.
I have read about message center but I am not sure how to implement it in this particular case. Would the message center be the best solution for this?
How do I implement a solution that will allow me to know which of the four pages is displayed?
Possible workaround would be to override OnCurrentPageChanged in your TabbedPage.
protected override void OnCurrentPageChanged()
{
base.OnCurrentPageChanged();
if ( CurrentPage is YourContentPage page)
{
page.YourCustomCode();
}
}
On the main TabbedPage, after you've added child pages, setting the CurrentPage property to null should fix the problem.
Related
I have a TabbedPage, which includes 3 pages (A,B,C). I need to detect (using some override method) when a page is active/selected from tabbed control. I tried some override methods such us OnAppearing with no result, because during debugging process I noticed OnAppearing was fired when TabbedPage was firstly initialized, so when I selected for example the second page (page B) this method was not fired. Is there any optimal way to detect switching between tabs inside child view?
Just like
ToolmakerSteve sayed, the tabbedpage has the CurrentPageChanged event, so you can override the OnCurrentPageChanged() method of the TabbedPage. Such as:
public partial class TabbedPage1 : TabbedPage
{
public TabbedPage1()
{
InitializeComponent();
}
protected override void OnCurrentPageChanged()
{
if(CurrentPage == Children[0])//Children[0] is the page A
{
....
}else if(CurrentPage == Children[1])//Children[1] is the page B
{
.....
}
else
{
......
}
base.OnCurrentPageChanged();
}
}
For the past 2 month I have been searching tirelessly for a way to implement a proper Page.Loaded event when using Xamarin.Forms but I couldn't implement or find a way to do it.
Most people suggest overriding Page.OnAppearing or adding an event handler for Page.Appearing both of which are not the answers or the proper way to achieve the desired effect and don't event behave as a real Page.Loaded event would.
I would like to know the following:
Why doesn't Xamarin.Forms have a built-in Page.Loaded event?
Is there's a work around?
Can I implement it from the native side?
Edit:
What I mean by "proper Page.Loaded" event is:
It must be called ONCE AND ONLY ONCE the page has loaded all of it's controls, laid them out, initialized them and rendered them for the first time.
It must NOT be called when returning from modal pages.
1.Why not load the data/controls in the constructor of the ContentPage? The constructor method is call only once and it is also called before Page.OnAppearing.
Can I implement it from the native side?
Yes, I think you can.
In iOS, override the ViewDidLoad method in custom renderer:
[assembly:ExportRenderer (typeof(ContentPage), typeof(MyPageRenderer))]
namespace App487.iOS
{
public class MyPageRenderer : PageRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
//call before ViewWillAppear and only called once
}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
}
}
}
In Android, try to override the OnAttachedToWindow method:
[assembly: ExportRenderer(typeof(ContentPage), typeof(MyPageRenderer))]
namespace App487.Droid
{
public class MyPageRenderer : PageRenderer
{
public MyPageRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
{
base.OnElementChanged(e);
}
protected override void OnAttachedToWindow()
{
base.OnAttachedToWindow();
}
}
}
Currently Xamarin.Forms doesn't not provide a proper/complete life cycle events to fulfill all specific requirements, but things are improving, the Dev team is currently working on to address this issue, below mentioned issues and recent pull request on the official GitHub Repos (you may follow, get ideas and maybe implement it yourself before they even ship it), they will for sure provide that in the future, although it is not clear when it will be ready.
Specification: Enhancement Add better life cycle events #2210.
Issue: LifeCycle events for controls #556.
Pull request: Life cycle events for controls
GitHub Branch where currently working on.
MAUI repo (Next evolution of Xamarin) Cross-Platform LifeCycle.
Specification Add Loaded/Unloaded to VisualElement.
I have implemented the swiping feature using SwipeGestureRecognizer on my homepage. But the problem is the home page is a child of a MasterDetailPage. So when I swipe to left in the homepage, the navigation drawer is also coming to UI. I have tried like below to stop showing navigation drawer on UI when doing SwipeGestureRecognizer using MessagingCenter, but no luck!!!
On Homepage
public void Swipe(object sender, EventArgs e)
{
MessagingCenter.Send<HomePage>(this, "HomePageSwipe");
//code for swipe
}
On MasterDetailPage Constructor
MessagingCenter.Subscribe<HomePage1>(this, "HomePageSwipe", (sender) =>
{
IsPresented = false;
NavigationPage.SetHasNavigationBar(this, false);
});
Is there any way to fix this?
I believe this behavior occurs only on ios. To disable this, you need to add this to the OnAppearing() method
if (Xamarin.Forms.Device.RuntimePlatform == Xamarin.Forms.Device.iOS)
{
IsGestureEnabled = false;
}
I have set up a FreshTabbedNavigationContainer with 5 pages.
Within the 5th tabbed page which is a SettingsPage where there is a way to display and AboutPage that is displayed via the SettingsPageModel like this
public Command AboutCommand
{
get
{
return new Command(() =>
{
CoreMethods.PushPageModel<AboutPageModel>();
});
}
}
When the user navigates away by selecting another tab, this other tab is displayed correctly.
If the user selects the SettingsPage via the tab, then the child AboutPage is automatically displayed.
I want to remove AboutPage from the navigation stack when another tab page is selected.
I have tried this in the AboutPage.xaml.cs
protected override void OnDisappearing()
{
base.OnDisappearing();
((AboutPageModel)BindingContext).CoreMethods.RemoveFromNavigation();
}
This works BUT if the back button is pressed on the app when in the AboutPage then it has already been removed from the navigation stack, and the app crashes.
How can I check if a PageModel is still in the navigation stack?
I have managed to resolve the problem :)
In the App.xaml.cs file in the App constructor where I create the FreshTabbedNavigationContainer, after setting the MainPage
MainPage = tabbedNavigation;
I then add the following code
tabbedNavigation.CurrentPageChanged += (sender, e) => {
tabbedNavigation.PopToRoot();
};
It works perfectly.
I am sorry, if this question is asked before, but I am unable to find my answer that is why I am asking again this question.
My Scenario is I have placed a back button on my axml views from which I am performing Navigation of Going back on previous views using GoBack() Method.
what I need I want to disable back button on my hardware so that my app should not go back to previous screens which are available in the navigation stack. I am using Prism MVVM for my app, so is there any possibility to disable this button or have some overrideable action method on my ViewModel from which I should stop it.
Hope you could understand my question.
B.R
I found the best way to do this was to use the provided override of OnBackPressed in the android MainActivity and then access a bool I saved somewhere. I use the settings plugin personally but the example below uses the built in application properties (it should work but I haven't tested it).
public class MainActivity : FormsApplicationActivity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
Forms.Init(this, bundle);
LoadApplication(new App());
}
public override void OnBackPressed()
{
var disable = (bool) App.Current.Properties["isBackButtonDisabled"];
if (disable) return;
base.OnBackPressed();
}
}