Programmatically switch between Tabs in a TabbedPage - c#

I have tabbed page with 4 children(4 tabs), and i want to override back button to allways set first 1 page when you push it. I tried several ways, this seems to make the most sense to me, but it doesn't work - tabbedPage is always null (when i override in all tabs)
protected override bool OnBackButtonPressed()
{
var tabbedPage = this.Parent as TabbedPage;
tabbedPage.CurrentPage = tabbedPage.Children[1];
return base.OnBackButtonPressed();
}
I tried to override this back button in TabbedPage Parent like this:
protected override bool OnBackButtonPressed()
{
if(CurrentPage == FirstPage)
{
return base.OnBackButtonPressed();
}
CurrentPage = FirstPage;
return true;
}
but it always close my app. Any idea why that tabbedPage is null for me?

My problem was that my children page is NavigationPage and I should use this.Parent.Parent to cast. So this is how it should be done when u use NavigaionPage as Children of TabbedPage
protected override bool OnBackButtonPressed()
{
var tabbedPage = this.Parent.Parent as TabbedPage;
tabbedPage.CurrentPage = tabbedPage.Children[0];
return true;
}

Firstly, when you have TabbedPage, OnBackButtonPressed is being invoked not in the ContentPage, but instead on the TabbedPage itself. So, the correct place to override the method is in the TabbedPage indeed.
Secondly, if you override the method in the TabbedPage itself, it will do the work, like this:
protected override bool OnBackButtonPressed()
{
var firstPage = Children[0];
if (CurrentPage == firstPage)
{
return base.OnBackButtonPressed();
}
CurrentPage = firstPage;
return true;
}
NB: Be careful what your Children collection is. If you have wrapped your pages in a NavigationPage, the check won't be correct.

You could set the current TabbedPage in App.xaml.cs when set the MainPage of App .
in App.xaml.cs
MainPage here is the TabbedPage in your project.
public partial class App : Application
{
public MainPage CurrentPage { get; }
public App()
{
InitializeComponent();
MainPage tabbedPage = new MainPage();
CurrentPage = tabbedPage;
DependencyService.Register<MockDataStore>();
MainPage = tabbedPage;
}
//...
}
And now you can access it in child page .
protected override bool OnBackButtonPressed()
{
App currentApp = Application.Current as App;
var tabbedpage = currentApp.CurrentPage;
tabbedpage.CurrentPage = tabbedpage.Children[0];
return true;
}
The above code works fine in my project. If it still doesn't work on your side, you could share a sample so that I can test it .

Related

How could I close my sidebar without closing my app in C# xamarin forms android?

I'm working with C# xamarin forms android and I'm trying to close my sidebar when the user touches de backbuttom but I'm not able to do it. Instead, my aplications closeses.
HomePage.xaml.cs code:
public partial class HomePage : ContentPage
{
string[] subs;
public HomePage()
{
//NavigationPage.SetHasBackButton(this, false);
InitializeComponent();
}
protected override bool OnBackButtonPressed()
{
return true;
}
}
my sidebar AppShell.xaml.cs code:
public partial class AppShell : Xamarin.Forms.Shell
{
public AppShell()
{
InitializeComponent();
nameuser.Title = Preferences.Get("displayName", "Default");
versionadoAPP.Text = "v" + $"{VersionTracking.CurrentBuild}.{VersionTracking.CurrentVersion}";
}
protected override bool OnBackButtonPressed()
{
return true;
}
}
Image of my app:
How could I resolve that?
Thank tou very much!
The easiest way that do this is to set the flyout presented property.
Try something like this:
Shell.Current.FlyoutIsPresented = false;
Good luck!

How to Extend Content Page

How can I extend the class Content Page to create a method that executes when it is the user's first time on a page?
(Xamarin.Forms)
This is probably the simplest way to do it:
public abstract class CustomContentPage : ContentPage
{
private bool _appeared;
protected override void OnAppearing()
{
base.OnAppearing();
if (!_appeared)
{
OnFirstAppearing();
_appeared = true;
}
}
protected abstract void OnFirstAppearing();
}
First you will want to use Application.Properties dictionary so you can preserve the state of the application, i.e. whether the user has ever gone to the page.
So in the OnAppearing method override in your ContentPage subclass, check to see if you have set the property in the Application.Current.Properties dictionary to see if the page has been visited. If the key is not present, set it and do whatever you want for this first visit to the page. If the key is present, do whatever you want to do for subsequent visits to the page, e.g.:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
protected override void OnAppearing()
{
base.OnAppearing();
if (!Application.Current.Properties.ContainsKey("main_page_visited"))
{
Application.Current.Properties["main_page_visited"] = true;
label.Text = "First Time visited";
}
else
{
label.Text = "Second+ Time visited";
}
}
}
The Application.Current.Properties gets saved automatically when the app exits.

Xamarin Forms Master Detail Keep Master on the left

I am trying to keep the Master page (menu) to the left of My MasterDetailPage at all times, I do not want the navigation to take the user away from the MasterDetailPage and make the user press a back button to get back.
I am looking a traditional burger bar menu to the left that simply changes the Detail page and keeps the master in place.
What I have now:
public partial class App : Application
{
public static NavigationPage NavPage { get; private set; }
private static RootPage RootPage;
public static bool MenuIsPresented
{
get
{
return RootPage.IsPresented;
}
set
{
RootPage.IsPresented = value;
}
}
public App()
{
InitializeComponent();
MenuPage menuPage = new MenuPage();
NavPage = new NavigationPage(new FirstPage());
RootPage = new RootPage();
RootPage.Master = menuPage;
RootPage.Detail = NavPage;
MainPage = RootPage;
}
...
}
And my ViewModel Command
async void GoSecondPageAsync(object obj)
{
await App.NavPage.PushAsync(new SecondPage());
App.MenuIsPresented = false;
}
But this just creates a new page on top of the stack with a back button back to the MasterDetailPage, while all I want is to stay within the MasterDetailPage.
You can push the new page and just remove the first one from the NavigationStack For example:
async void GoSecondPageAsync(object obj)
{
await App.NavPage.PushAsync(new SecondPage());
var removePage = App.NavPage.Navigation.NavigationStack[0];
App.NavPage.Navigation.RemovePage(removePage);
App.MenuIsPresented = false;
}
Although, if you just always want to replace the page do you really even need the NavigationPage and can't you just set the RootPage.Detail=new SecondPage();
You just need to update the Detail property to point to the new page. Like this:
async void GoSecondPageAsync(object obj)
{
RootPage.Detail = new NavigationPage(new SecondPage());
App.MenuIsPresented = false;
}

OnBackButtonPressed Not Firing Xamarin Forms

I am trying to prevent the user of my app from pressing the hardware back button.
I have found this code snippet that is in the code behind the xaml file:
protected override bool OnBackButtonPressed()
{
return true;
}
I have tried variations of this including using Boolean instead of Bool and returning base.functionname nothing seems to fire this method.
Here is the bigger context:
Code behind:
namespace Watson.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class StartScan : ContentPage
{
public StartScan()
{
InitializeComponent();
}
protected override bool OnBackButtonPressed()
{
return true;
}
}
}
This is the second page in the stack and disabling the button only needs to happen on this page only, no where else.
Any help would be appreciated.
This is working for me, I tried in Android and iOS platforms using Xamarin.Forms.
Hope you can resolve with this piece of code.
namespace Test
{
public partial class TestPage2 : ContentPage
{
public TestPage2()
{
NavigationPage.SetHasBackButton(this, false);
InitializeComponent();
}
protected override bool OnBackButtonPressed()
{
//return base.OnBackButtonPressed();
return true;
}
}
}
Thanks,
You can also add NavigationPage.SetHasBackButton property in the XAML
NavigationPage.HasBackButton="True"
In the Content Page
You can do this way:
namespace Watson.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class StartScan : ContentPage
{
public StartScan()
{
NavigationPage.SetHasBackButton(this, false);
InitializeComponent();
}
protected override bool OnBackButtonPressed()
{
// you can put some actions here (for example, an dialog prompt, ...)
return true;
}
}
}
For me it is working with the following code (Samsung Android)
protected override bool OnBackButtonPressed()
{
//base.OnBackButtonPressed();
browser.GoBack();
return true;
}
OnBackButtonPressed firing when you click the back button on your device, not from your navigation page, do your logic in OnDisappearing!

OnAppearing in children of TabbedPage is triggered only once

I have a TabbedPage in Xamarin.Forms:
public partial class MainPage : TabbedPage
{
public MainPage()
{
InitializeComponent();
var playPage = new NavigationPage(new PlayPage())
{
Title = "Play",
Icon = "play1.png"
};
var settingsPage = new NavigationPage(new SettingsPage())
{
Title = "Settings",
Icon = "settings.png"
};
var aboutPage = new NavigationPage(new AboutPage())
{
Title = "About",
Icon = "about.png"
};
Children.Add(playPage);
Children.Add(settingsPage);
Children.Add(aboutPage);
}
Each of the child pages are a ContentPage that overrides the OnAppearing method. The content of my child pages are not updating properly when I navigate between the tabs and further debugging tells me that the OnAppearing method for child pages are only called once (when the MainPage is first loaded).
Anyone have any idea why the OnAppearing method is only called once? And how can I solve this issue?
More Info
My child pages such SettingsPage contains events that when fired open another ContentPage using Navigation.PushAsync method. I expected the OnAppearing method to also get called when switching from tab pages and the navigation pages within those tab pages. (Hope this makes sense)
It only triggers once since the View is not destroyed when you navigate between tabs.
You can use the CurrentPageChanged event to figure our that a page has changed and signal the view it changes to and do whatever update of the view you need.
this.CurrentPageChanged += PageChanged;
void PageChanged(object sender, EventArgs args)
{
var currentPage = CurrentPage as MyTabPage;
currentPage?.UpdateView();
}
Then in your page:
public void UpdateView()
{
// do whatever you need here to update the page
}
Do not embedded your ContentPages within a "single" level NavigationPage.
The following works fine in terms of the OnAppearing event firing when switching between tabs:
public class PlayPage : ContentPage
{
protected override void OnAppearing()
{
System.Diagnostics.Debug.WriteLine("PlayPage");
base.OnAppearing();
}
}
public class AboutPage : ContentPage
{
protected override void OnAppearing()
{
System.Diagnostics.Debug.WriteLine("AboutPage");
base.OnAppearing();
}
}
public class SettingsPage : ContentPage
{
protected override void OnAppearing()
{
System.Diagnostics.Debug.WriteLine("SettingPage");
base.OnAppearing();
}
}
public partial class MainPage : TabbedPage
{
public MainPage()
{
var playPage = new PlayPage() { Title = "Play" };
var settingsPage = new SettingsPage() { Title = "Settings" };
var aboutPage = new AboutPage() { Title = "About" };
Children.Add(playPage);
Children.Add(settingsPage);
Children.Add(aboutPage);
}
}
public class App : Application
{
public App()
{
this.MainPage = new MainPage();
}
}

Categories